diff --git a/.fern/metadata.json b/.fern/metadata.json
new file mode 100644
index 0000000..44a2882
--- /dev/null
+++ b/.fern/metadata.json
@@ -0,0 +1,14 @@
+{
+ "cliVersion": "4.22.0",
+ "generatorName": "fernapi/fern-python-sdk",
+ "generatorVersion": "4.63.4",
+ "generatorConfig": {
+ "client_class_name": "Webflow",
+ "improved_imports": false,
+ "pydantic_config": {
+ "use_str_enums": false
+ }
+ },
+ "originGitCommit": "3ad89f5558f1774e8535f034a87bfe8c2fdfcd50",
+ "sdkVersion": "2.0.0"
+}
\ No newline at end of file
diff --git a/.fernignore b/.fernignore
index b6293ae..e83159b 100644
--- a/.fernignore
+++ b/.fernignore
@@ -4,3 +4,4 @@ README.md
assets/
src/webflow/oauth.py
+src/webflow/types/oauth_scope.py
\ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0b26bf2..bab604b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,16 +1,20 @@
name: ci
-
on: [push]
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: false
+
jobs:
compile:
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
steps:
- name: Checkout repo
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Set up python
uses: actions/setup-python@v4
with:
- python-version: 3.8
+ python-version: 3.9
- name: Bootstrap poetry
run: |
curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1
@@ -19,33 +23,34 @@ jobs:
- name: Compile
run: poetry run mypy .
test:
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
steps:
- name: Checkout repo
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Set up python
uses: actions/setup-python@v4
with:
- python-version: 3.8
+ python-version: 3.9
- name: Bootstrap poetry
run: |
curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1
- name: Install dependencies
run: poetry install
+
- name: Test
- run: poetry run pytest .
+ run: poetry run pytest -rP -n auto .
publish:
needs: [compile, test]
if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
steps:
- name: Checkout repo
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Set up python
uses: actions/setup-python@v4
with:
- python-version: 3.8
+ python-version: 3.9
- name: Bootstrap poetry
run: |
curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1
diff --git a/.gitignore b/.gitignore
index 42cb863..d2e4ca8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
-dist/
.mypy_cache/
+.ruff_cache/
__pycache__/
+dist/
poetry.toml
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..eb82e56
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2026 Webflow.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/README.md b/README.md
index 5bd81ef..e6cc6cc 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
[](https://github.com/fern-api/fern)
[](https://pypi.python.org/pypi/webflow)
-The Webflow Python Library provides convenient access to the [Webflow Data API](https://developers.webflow.com/reference/rest-introduction) from
+The Webflow Python Library provides convenient access to the [Webflow Data API](https://developers.webflow.com/data/reference/rest-introduction) from
applications written in Python.
The library includes type definitions for all
@@ -55,12 +55,12 @@ asyncio.run(main())
## OAuth
-To implement OAuth, you'll need to [register a Webflow App in your Workspace](https://developers.webflow.com/reference/authorization)
+To implement OAuth, you'll need to [register a Webflow App in your Workspace](https://developers.webflow.com/data/reference/authentication)
### Step 1: Authorize URL
The first step in OAuth is to generate an Authorization URL. Use this URL
-to fetch your Authorization Code. See the [docs](https://docs.developers.webflow.com/v1.0.0/docs/oauth#user-authorization)
+to fetch your Authorization Code. See the [docs](https://developers.webflow.com/data/reference/oauth-app#2-create-an-authorization-link)
for more details.
```python
@@ -106,7 +106,7 @@ client = Webflow(
All of the models are nested within the Webflow module. Let IntelliSense
guide you!
-
+
## Exception Handling
All errors thrown by the SDK will be subclasses of [`ApiError`](./src/webflow/core/api_error.py).
diff --git a/poetry.lock b/poetry.lock
index d0145b2..83fdc8b 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,14 +1,14 @@
-# This file is automatically @generated by Poetry 1.8.1 and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand.
[[package]]
name = "annotated-types"
-version = "0.6.0"
+version = "0.7.0"
description = "Reusable constraint types to use with typing.Annotated"
optional = false
python-versions = ">=3.8"
files = [
- {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"},
- {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"},
+ {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"},
+ {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
]
[package.dependencies]
@@ -16,13 +16,13 @@ typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""}
[[package]]
name = "anyio"
-version = "4.3.0"
+version = "4.5.2"
description = "High level compatibility layer for multiple asynchronous event loop implementations"
optional = false
python-versions = ">=3.8"
files = [
- {file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"},
- {file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"},
+ {file = "anyio-4.5.2-py3-none-any.whl", hash = "sha256:c011ee36bc1e8ba40e5a81cb9df91925c218fe9b778554e0b56a21e1b5d4716f"},
+ {file = "anyio-4.5.2.tar.gz", hash = "sha256:23009af4ed04ce05991845451e11ef02fc7c5ed29179ac9a420e5ad0ac7ddc5b"},
]
[package.dependencies]
@@ -32,19 +32,19 @@ sniffio = ">=1.1"
typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""}
[package.extras]
-doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"]
-test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"]
-trio = ["trio (>=0.23)"]
+doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"]
+test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"]
+trio = ["trio (>=0.26.1)"]
[[package]]
name = "certifi"
-version = "2024.2.2"
+version = "2026.2.25"
description = "Python package for providing Mozilla's CA Bundle."
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
files = [
- {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"},
- {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"},
+ {file = "certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa"},
+ {file = "certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7"},
]
[[package]]
@@ -60,59 +60,76 @@ files = [
[[package]]
name = "exceptiongroup"
-version = "1.2.0"
+version = "1.3.1"
description = "Backport of PEP 654 (exception groups)"
optional = false
python-versions = ">=3.7"
files = [
- {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"},
- {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"},
+ {file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"},
+ {file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"},
]
+[package.dependencies]
+typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""}
+
[package.extras]
test = ["pytest (>=6)"]
+[[package]]
+name = "execnet"
+version = "2.1.2"
+description = "execnet: rapid multi-Python deployment"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec"},
+ {file = "execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd"},
+]
+
+[package.extras]
+testing = ["hatch", "pre-commit", "pytest", "tox"]
+
[[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.5"
+version = "1.0.9"
description = "A minimal low-level HTTP client."
optional = false
python-versions = ">=3.8"
files = [
- {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"},
- {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"},
+ {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)"]
http2 = ["h2 (>=3,<5)"]
socks = ["socksio (==1.*)"]
-trio = ["trio (>=0.22.0,<0.26.0)"]
+trio = ["trio (>=0.22.0,<1.0)"]
[[package]]
name = "httpx"
-version = "0.27.0"
+version = "0.28.1"
description = "The next generation HTTP client."
optional = false
python-versions = ">=3.8"
files = [
- {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"},
- {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"},
+ {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"},
+ {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"},
]
[package.dependencies]
@@ -120,114 +137,123 @@ anyio = "*"
certifi = "*"
httpcore = "==1.*"
idna = "*"
-sniffio = "*"
[package.extras]
brotli = ["brotli", "brotlicffi"]
cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"]
http2 = ["h2 (>=3,<5)"]
socks = ["socksio (==1.*)"]
+zstd = ["zstandard (>=0.18.0)"]
[[package]]
name = "idna"
-version = "3.6"
+version = "3.11"
description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.8"
files = [
- {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"},
- {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"},
+ {file = "idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea"},
+ {file = "idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"},
]
+[package.extras]
+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]]
name = "mypy"
-version = "1.9.0"
+version = "1.13.0"
description = "Optional static typing for Python"
optional = false
python-versions = ">=3.8"
files = [
- {file = "mypy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f8a67616990062232ee4c3952f41c779afac41405806042a8126fe96e098419f"},
- {file = "mypy-1.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d357423fa57a489e8c47b7c85dfb96698caba13d66e086b412298a1a0ea3b0ed"},
- {file = "mypy-1.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49c87c15aed320de9b438ae7b00c1ac91cd393c1b854c2ce538e2a72d55df150"},
- {file = "mypy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:48533cdd345c3c2e5ef48ba3b0d3880b257b423e7995dada04248725c6f77374"},
- {file = "mypy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:4d3dbd346cfec7cb98e6cbb6e0f3c23618af826316188d587d1c1bc34f0ede03"},
- {file = "mypy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:653265f9a2784db65bfca694d1edd23093ce49740b2244cde583aeb134c008f3"},
- {file = "mypy-1.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a3c007ff3ee90f69cf0a15cbcdf0995749569b86b6d2f327af01fd1b8aee9dc"},
- {file = "mypy-1.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2418488264eb41f69cc64a69a745fad4a8f86649af4b1041a4c64ee61fc61129"},
- {file = "mypy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:68edad3dc7d70f2f17ae4c6c1b9471a56138ca22722487eebacfd1eb5321d612"},
- {file = "mypy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:85ca5fcc24f0b4aeedc1d02f93707bccc04733f21d41c88334c5482219b1ccb3"},
- {file = "mypy-1.9.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aceb1db093b04db5cd390821464504111b8ec3e351eb85afd1433490163d60cd"},
- {file = "mypy-1.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0235391f1c6f6ce487b23b9dbd1327b4ec33bb93934aa986efe8a9563d9349e6"},
- {file = "mypy-1.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4d5ddc13421ba3e2e082a6c2d74c2ddb3979c39b582dacd53dd5d9431237185"},
- {file = "mypy-1.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:190da1ee69b427d7efa8aa0d5e5ccd67a4fb04038c380237a0d96829cb157913"},
- {file = "mypy-1.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:fe28657de3bfec596bbeef01cb219833ad9d38dd5393fc649f4b366840baefe6"},
- {file = "mypy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e54396d70be04b34f31d2edf3362c1edd023246c82f1730bbf8768c28db5361b"},
- {file = "mypy-1.9.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5e6061f44f2313b94f920e91b204ec600982961e07a17e0f6cd83371cb23f5c2"},
- {file = "mypy-1.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a10926e5473c5fc3da8abb04119a1f5811a236dc3a38d92015cb1e6ba4cb9e"},
- {file = "mypy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b685154e22e4e9199fc95f298661deea28aaede5ae16ccc8cbb1045e716b3e04"},
- {file = "mypy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:5d741d3fc7c4da608764073089e5f58ef6352bedc223ff58f2f038c2c4698a89"},
- {file = "mypy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:587ce887f75dd9700252a3abbc9c97bbe165a4a630597845c61279cf32dfbf02"},
- {file = "mypy-1.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f88566144752999351725ac623471661c9d1cd8caa0134ff98cceeea181789f4"},
- {file = "mypy-1.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61758fabd58ce4b0720ae1e2fea5cfd4431591d6d590b197775329264f86311d"},
- {file = "mypy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e49499be624dead83927e70c756970a0bc8240e9f769389cdf5714b0784ca6bf"},
- {file = "mypy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:571741dc4194b4f82d344b15e8837e8c5fcc462d66d076748142327626a1b6e9"},
- {file = "mypy-1.9.0-py3-none-any.whl", hash = "sha256:a260627a570559181a9ea5de61ac6297aa5af202f06fd7ab093ce74e7181e43e"},
- {file = "mypy-1.9.0.tar.gz", hash = "sha256:3cc5da0127e6a478cddd906068496a97a7618a21ce9b54bde5bf7e539c7af974"},
+ {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"},
+ {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"},
+ {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"},
+ {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"},
+ {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"},
+ {file = "mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d"},
+ {file = "mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d"},
+ {file = "mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b"},
+ {file = "mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73"},
+ {file = "mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca"},
+ {file = "mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5"},
+ {file = "mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e"},
+ {file = "mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2"},
+ {file = "mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0"},
+ {file = "mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2"},
+ {file = "mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7"},
+ {file = "mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62"},
+ {file = "mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8"},
+ {file = "mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7"},
+ {file = "mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc"},
+ {file = "mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a"},
+ {file = "mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb"},
+ {file = "mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b"},
+ {file = "mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74"},
+ {file = "mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6"},
+ {file = "mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc"},
+ {file = "mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732"},
+ {file = "mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc"},
+ {file = "mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d"},
+ {file = "mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24"},
+ {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"},
+ {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"},
]
[package.dependencies]
mypy-extensions = ">=1.0.0"
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
-typing-extensions = ">=4.1.0"
+typing-extensions = ">=4.6.0"
[package.extras]
dmypy = ["psutil (>=4.0)"]
+faster-cache = ["orjson"]
install-types = ["pip"]
mypyc = ["setuptools (>=50)"]
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.0"
+version = "26.0"
description = "Core utilities for Python packages"
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"},
- {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"},
+ {file = "packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529"},
+ {file = "packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4"},
]
[[package]]
name = "pluggy"
-version = "1.4.0"
+version = "1.5.0"
description = "plugin and hook calling mechanisms for python"
optional = false
python-versions = ">=3.8"
files = [
- {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"},
- {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"},
+ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
+ {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
]
[package.extras]
@@ -236,109 +262,131 @@ testing = ["pytest", "pytest-benchmark"]
[[package]]
name = "pydantic"
-version = "2.6.4"
+version = "2.10.6"
description = "Data validation using Python type hints"
optional = false
python-versions = ">=3.8"
files = [
- {file = "pydantic-2.6.4-py3-none-any.whl", hash = "sha256:cc46fce86607580867bdc3361ad462bab9c222ef042d3da86f2fb333e1d916c5"},
- {file = "pydantic-2.6.4.tar.gz", hash = "sha256:b1704e0847db01817624a6b86766967f552dd9dbf3afba4004409f908dcc84e6"},
+ {file = "pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584"},
+ {file = "pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"},
]
[package.dependencies]
-annotated-types = ">=0.4.0"
-pydantic-core = "2.16.3"
-typing-extensions = ">=4.6.1"
+annotated-types = ">=0.6.0"
+pydantic-core = "2.27.2"
+typing-extensions = ">=4.12.2"
[package.extras]
email = ["email-validator (>=2.0.0)"]
+timezone = ["tzdata"]
[[package]]
name = "pydantic-core"
-version = "2.16.3"
-description = ""
+version = "2.27.2"
+description = "Core functionality for Pydantic validation and serialization"
optional = false
python-versions = ">=3.8"
files = [
- {file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"},
- {file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"},
- {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"},
- {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"},
- {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"},
- {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"},
- {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"},
- {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"},
- {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"},
- {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"},
- {file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"},
- {file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"},
- {file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"},
- {file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"},
- {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"},
- {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"},
- {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"},
- {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"},
- {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"},
- {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"},
- {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"},
- {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"},
- {file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"},
- {file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"},
- {file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"},
- {file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff"},
- {file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975"},
- {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2"},
- {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120"},
- {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053"},
- {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b"},
- {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade"},
- {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e"},
- {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca"},
- {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf"},
- {file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe"},
- {file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed"},
- {file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6"},
- {file = "pydantic_core-2.16.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01"},
- {file = "pydantic_core-2.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7"},
- {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48"},
- {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a"},
- {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8"},
- {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d"},
- {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9"},
- {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c"},
- {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8"},
- {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5"},
- {file = "pydantic_core-2.16.3-cp38-none-win32.whl", hash = "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a"},
- {file = "pydantic_core-2.16.3-cp38-none-win_amd64.whl", hash = "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed"},
- {file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"},
- {file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"},
- {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"},
- {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"},
- {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"},
- {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"},
- {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"},
- {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"},
- {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"},
- {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"},
- {file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"},
- {file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"},
- {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"},
- {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"},
- {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"},
- {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"},
- {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"},
- {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"},
- {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"},
- {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"},
- {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"},
- {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"},
- {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"},
- {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"},
- {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"},
- {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"},
- {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"},
- {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"},
- {file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"},
+ {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"},
+ {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"},
+ {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a"},
+ {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5"},
+ {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c"},
+ {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7"},
+ {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a"},
+ {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236"},
+ {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962"},
+ {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9"},
+ {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af"},
+ {file = "pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4"},
+ {file = "pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31"},
+ {file = "pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc"},
+ {file = "pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7"},
+ {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15"},
+ {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306"},
+ {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99"},
+ {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459"},
+ {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048"},
+ {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d"},
+ {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b"},
+ {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474"},
+ {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6"},
+ {file = "pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c"},
+ {file = "pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc"},
+ {file = "pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4"},
+ {file = "pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0"},
+ {file = "pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef"},
+ {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7"},
+ {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934"},
+ {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6"},
+ {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c"},
+ {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2"},
+ {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4"},
+ {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3"},
+ {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4"},
+ {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57"},
+ {file = "pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc"},
+ {file = "pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9"},
+ {file = "pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b"},
+ {file = "pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b"},
+ {file = "pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154"},
+ {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9"},
+ {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9"},
+ {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1"},
+ {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a"},
+ {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e"},
+ {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4"},
+ {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27"},
+ {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee"},
+ {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1"},
+ {file = "pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130"},
+ {file = "pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee"},
+ {file = "pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b"},
+ {file = "pydantic_core-2.27.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506"},
+ {file = "pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320"},
+ {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145"},
+ {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1"},
+ {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228"},
+ {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046"},
+ {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5"},
+ {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a"},
+ {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d"},
+ {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9"},
+ {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da"},
+ {file = "pydantic_core-2.27.2-cp38-cp38-win32.whl", hash = "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b"},
+ {file = "pydantic_core-2.27.2-cp38-cp38-win_amd64.whl", hash = "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad"},
+ {file = "pydantic_core-2.27.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993"},
+ {file = "pydantic_core-2.27.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308"},
+ {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4"},
+ {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf"},
+ {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76"},
+ {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118"},
+ {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630"},
+ {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54"},
+ {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f"},
+ {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362"},
+ {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96"},
+ {file = "pydantic_core-2.27.2-cp39-cp39-win32.whl", hash = "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e"},
+ {file = "pydantic_core-2.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67"},
+ {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e"},
+ {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8"},
+ {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3"},
+ {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f"},
+ {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133"},
+ {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc"},
+ {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50"},
+ {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9"},
+ {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151"},
+ {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656"},
+ {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278"},
+ {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb"},
+ {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd"},
+ {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc"},
+ {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b"},
+ {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b"},
+ {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2"},
+ {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35"},
+ {file = "pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39"},
]
[package.dependencies]
@@ -366,6 +414,96 @@ tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
[package.extras]
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
+[[package]]
+name = "pytest-asyncio"
+version = "0.23.8"
+description = "Pytest support for asyncio"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pytest_asyncio-0.23.8-py3-none-any.whl", hash = "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2"},
+ {file = "pytest_asyncio-0.23.8.tar.gz", hash = "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3"},
+]
+
+[package.dependencies]
+pytest = ">=7.0.0,<9"
+
+[package.extras]
+docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"]
+testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"]
+
+[[package]]
+name = "pytest-xdist"
+version = "3.6.1"
+description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7"},
+ {file = "pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d"},
+]
+
+[package.dependencies]
+execnet = ">=2.1"
+pytest = ">=7.0.0"
+
+[package.extras]
+psutil = ["psutil (>=3.0)"]
+setproctitle = ["setproctitle"]
+testing = ["filelock"]
+
+[[package]]
+name = "python-dateutil"
+version = "2.9.0.post0"
+description = "Extensions to the standard Python datetime module"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+files = [
+ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
+ {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
+]
+
+[package.dependencies]
+six = ">=1.5"
+
+[[package]]
+name = "ruff"
+version = "0.11.5"
+description = "An extremely fast Python linter and code formatter, written in Rust."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "ruff-0.11.5-py3-none-linux_armv6l.whl", hash = "sha256:2561294e108eb648e50f210671cc56aee590fb6167b594144401532138c66c7b"},
+ {file = "ruff-0.11.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ac12884b9e005c12d0bd121f56ccf8033e1614f736f766c118ad60780882a077"},
+ {file = "ruff-0.11.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:4bfd80a6ec559a5eeb96c33f832418bf0fb96752de0539905cf7b0cc1d31d779"},
+ {file = "ruff-0.11.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0947c0a1afa75dcb5db4b34b070ec2bccee869d40e6cc8ab25aca11a7d527794"},
+ {file = "ruff-0.11.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ad871ff74b5ec9caa66cb725b85d4ef89b53f8170f47c3406e32ef040400b038"},
+ {file = "ruff-0.11.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e6cf918390cfe46d240732d4d72fa6e18e528ca1f60e318a10835cf2fa3dc19f"},
+ {file = "ruff-0.11.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:56145ee1478582f61c08f21076dc59153310d606ad663acc00ea3ab5b2125f82"},
+ {file = "ruff-0.11.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e5f66f8f1e8c9fc594cbd66fbc5f246a8d91f916cb9667e80208663ec3728304"},
+ {file = "ruff-0.11.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80b4df4d335a80315ab9afc81ed1cff62be112bd165e162b5eed8ac55bfc8470"},
+ {file = "ruff-0.11.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3068befab73620b8a0cc2431bd46b3cd619bc17d6f7695a3e1bb166b652c382a"},
+ {file = "ruff-0.11.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f5da2e710a9641828e09aa98b92c9ebbc60518fdf3921241326ca3e8f8e55b8b"},
+ {file = "ruff-0.11.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ef39f19cb8ec98cbc762344921e216f3857a06c47412030374fffd413fb8fd3a"},
+ {file = "ruff-0.11.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b2a7cedf47244f431fd11aa5a7e2806dda2e0c365873bda7834e8f7d785ae159"},
+ {file = "ruff-0.11.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:81be52e7519f3d1a0beadcf8e974715b2dfc808ae8ec729ecfc79bddf8dbb783"},
+ {file = "ruff-0.11.5-py3-none-win32.whl", hash = "sha256:e268da7b40f56e3eca571508a7e567e794f9bfcc0f412c4b607931d3af9c4afe"},
+ {file = "ruff-0.11.5-py3-none-win_amd64.whl", hash = "sha256:6c6dc38af3cfe2863213ea25b6dc616d679205732dc0fb673356c2d69608f800"},
+ {file = "ruff-0.11.5-py3-none-win_arm64.whl", hash = "sha256:67e241b4314f4eacf14a601d586026a962f4002a475aa702c69980a38087aa4e"},
+ {file = "ruff-0.11.5.tar.gz", hash = "sha256:cae2e2439cb88853e421901ec040a758960b576126dab520fa08e9de431d1bef"},
+]
+
+[[package]]
+name = "six"
+version = "1.17.0"
+description = "Python 2 and 3 compatibility utilities"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+files = [
+ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"},
+ {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"},
+]
+
[[package]]
name = "sniffio"
version = "1.3.1"
@@ -379,27 +517,83 @@ files = [
[[package]]
name = "tomli"
-version = "2.0.1"
+version = "2.4.0"
description = "A lil' TOML parser"
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
+files = [
+ {file = "tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867"},
+ {file = "tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9"},
+ {file = "tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95"},
+ {file = "tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76"},
+ {file = "tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d"},
+ {file = "tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576"},
+ {file = "tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a"},
+ {file = "tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa"},
+ {file = "tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614"},
+ {file = "tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1"},
+ {file = "tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8"},
+ {file = "tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a"},
+ {file = "tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1"},
+ {file = "tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b"},
+ {file = "tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51"},
+ {file = "tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729"},
+ {file = "tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da"},
+ {file = "tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3"},
+ {file = "tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0"},
+ {file = "tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e"},
+ {file = "tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4"},
+ {file = "tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e"},
+ {file = "tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c"},
+ {file = "tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f"},
+ {file = "tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86"},
+ {file = "tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87"},
+ {file = "tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132"},
+ {file = "tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6"},
+ {file = "tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc"},
+ {file = "tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66"},
+ {file = "tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d"},
+ {file = "tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702"},
+ {file = "tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8"},
+ {file = "tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776"},
+ {file = "tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475"},
+ {file = "tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2"},
+ {file = "tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9"},
+ {file = "tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0"},
+ {file = "tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df"},
+ {file = "tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d"},
+ {file = "tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f"},
+ {file = "tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b"},
+ {file = "tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087"},
+ {file = "tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd"},
+ {file = "tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4"},
+ {file = "tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a"},
+ {file = "tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c"},
+]
+
+[[package]]
+name = "types-python-dateutil"
+version = "2.9.0.20241206"
+description = "Typing stubs for python-dateutil"
+optional = false
+python-versions = ">=3.8"
files = [
- {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
- {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
+ {file = "types_python_dateutil-2.9.0.20241206-py3-none-any.whl", hash = "sha256:e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53"},
+ {file = "types_python_dateutil-2.9.0.20241206.tar.gz", hash = "sha256:18f493414c26ffba692a72369fea7a154c502646301ebfe3d56a04b3767284cb"},
]
[[package]]
name = "typing-extensions"
-version = "4.10.0"
+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.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"},
- {file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"},
+ {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]
lock-version = "2.0"
python-versions = "^3.8"
-content-hash = "3c8fae8de68e5484c48073bf191e51acbe3b9a32fd98e6b5e4d165e42a7fc7aa"
+content-hash = "bcf31a142c86d9e556553c8c260a93b563ac64a043076dbd48b26111d422c26e"
diff --git a/pyproject.toml b/pyproject.toml
index 2ade12a..786103a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,22 +1,89 @@
+[project]
+name = "webflow"
+dynamic = ["version"]
+
[tool.poetry]
name = "webflow"
-version = "v1.2.0"
+version = "2.0.0"
description = ""
readme = "README.md"
authors = []
+keywords = []
+license = "MIT"
+classifiers = [
+ "Intended Audience :: Developers",
+ "Programming Language :: Python",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3.12",
+ "Programming Language :: Python :: 3.13",
+ "Programming Language :: Python :: 3.14",
+ "Programming Language :: Python :: 3.15",
+ "Operating System :: OS Independent",
+ "Operating System :: POSIX",
+ "Operating System :: MacOS",
+ "Operating System :: POSIX :: Linux",
+ "Operating System :: Microsoft :: Windows",
+ "Topic :: Software Development :: Libraries :: Python Modules",
+ "Typing :: Typed",
+ "License :: OSI Approved :: MIT License"
+]
packages = [
{ include = "webflow", from = "src"}
]
+[tool.poetry.urls]
+Repository = 'https://github.com/webflow/webflow-python'
+
[tool.poetry.dependencies]
python = "^3.8"
httpx = ">=0.21.2"
pydantic = ">= 1.9.2"
+pydantic-core = ">=2.18.2"
typing_extensions = ">= 4.0.0"
-[tool.poetry.dev-dependencies]
-mypy = "^1.8.0"
+[tool.poetry.group.dev.dependencies]
+mypy = "==1.13.0"
pytest = "^7.4.0"
+pytest-asyncio = "^0.23.5"
+pytest-xdist = "^3.6.1"
+python-dateutil = "^2.9.0"
+types-python-dateutil = "^2.9.0.20240316"
+ruff = "==0.11.5"
+
+[tool.pytest.ini_options]
+testpaths = [ "tests" ]
+asyncio_mode = "auto"
+
+[tool.mypy]
+plugins = ["pydantic.mypy"]
+
+[tool.ruff]
+line-length = 120
+
+[tool.ruff.lint]
+select = [
+ "E", # pycodestyle errors
+ "F", # pyflakes
+ "I", # isort
+]
+ignore = [
+ "E402", # Module level import not at top of file
+ "E501", # Line too long
+ "E711", # Comparison to `None` should be `cond is not None`
+ "E712", # Avoid equality comparisons to `True`; use `if ...:` checks
+ "E721", # Use `is` and `is not` for type comparisons, or `isinstance()` for insinstance checks
+ "E722", # Do not use bare `except`
+ "E731", # Do not assign a `lambda` expression, use a `def`
+ "F821", # Undefined name
+ "F841" # Local variable ... is assigned to but never used
+]
+
+[tool.ruff.lint.isort]
+section-order = ["future", "standard-library", "third-party", "first-party"]
[build-system]
requires = ["poetry-core"]
diff --git a/reference.md b/reference.md
new file mode 100644
index 0000000..fbfbd16
--- /dev/null
+++ b/reference.md
@@ -0,0 +1,10448 @@
+# Reference
+## Token
+client.token.authorized_by () -> AuthorizedUser
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Information about the Authorized User
+
+Required Scope | `authorized_user:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.token.authorized_by()
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.token.introspect () -> Authorization
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Information about the authorization token
+
+Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients).
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.token.introspect()
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Sites
+client.sites.create (...) -> Site
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Create a site.
+
+This endpoint requires an Enterprise workspace.
+
+Required scope | `workspace:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.create(
+ workspace_id="580e63e98c9a982ac9b8b741",
+ name="The Hitchhiker\'s Guide to the Galaxy",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**workspace_id:** `str` — Unique identifier for a Workspace
+
+
+
+
+
+
+
+**name:** `str` — The name of the site
+
+
+
+
+
+
+
+**template_name:** `typing.Optional[str]` — The workspace or marketplace template to use
+
+
+
+
+
+
+
+**parent_folder_id:** `typing.Optional[str]` — MegaDodo Publications - Potential Book Ideas
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.sites.list () -> Sites
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+List of all sites the provided access token is able to access.
+
+Required scope | `sites:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.list()
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.sites.get (...) -> Site
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Get details of a site.
+
+Required scope | `sites:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.get(
+ site_id="580e63e98c9a982ac9b8b741",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.sites.delete (...)
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Delete a site.
+
+This endpoint requires an Enterprise workspace.
+
+Required scope | `sites:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.delete(
+ site_id="580e63e98c9a982ac9b8b741",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.sites.update (...) -> Site
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Update a site.
+
+This endpoint requires an Enterprise workspace.
+
+Required scope | `sites:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.update(
+ site_id="580e63e98c9a982ac9b8b741",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**name:** `typing.Optional[str]` — The name of the site
+
+
+
+
+
+
+
+**parent_folder_id:** `typing.Optional[str]` — The parent folder ID of the site
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.sites.get_custom_domain (...) -> Domains
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Get a list of all custom domains related to site.
+
+Required scope | `sites:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.get_custom_domain(
+ site_id="580e63e98c9a982ac9b8b741",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.sites.publish (...) -> SitesPublishResponse
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+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 specific rate limit of one successful publish queue per minute.
+
+Required scope | `sites:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.publish(
+ site_id="580e63e98c9a982ac9b8b741",
+ custom_domains=[
+ "660c6449dd97ebc7346ac629",
+ "660c6449dd97ebc7346ac62f"
+ ],
+ publish_to_webflow_subdomain=False,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**custom_domains:** `typing.Optional[typing.List[str]]` — Array of Custom Domain IDs to publish
+
+
+
+
+
+
+
+**publish_to_webflow_subdomain:** `typing.Optional[bool]` — Choice of whether to publish to the default Webflow Subdomain
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Collections
+client.collections.list (...) -> CollectionList
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+List of all Collections within a Site.
+
+Required scope | `cms:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.list(
+ site_id="580e63e98c9a982ac9b8b741",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.collections.create (...) -> Collection
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+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`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow, StaticField
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.create(
+ 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",
+ ),
+ StaticField(
+ is_required=True,
+ type=,
+ display_name="Author",
+ help_text="The author of the blog post",
+ )
+ ],
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**display_name:** `str` — Name of the collection. Each collection name must be distinct.
+
+
+
+
+
+
+
+**singular_name:** `str` — Singular name of each item.
+
+
+
+
+
+
+
+**slug:** `typing.Optional[str]` — Part of a URL that identifier
+
+
+
+
+
+
+
+**fields:** `typing.Optional[typing.List[FieldCreate]]` — An array of custom fields to add to the collection
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.collections.get (...) -> Collection
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Get the full details of a collection from its ID.
+
+Required scope | `cms:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.get(
+ collection_id="580e63fc8c9a982ac9b8b745",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**collection_id:** `str` — Unique identifier for a Collection
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.collections.delete (...)
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Delete a collection using its ID.
+
+Required scope | `cms:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.delete(
+ collection_id="580e63fc8c9a982ac9b8b745",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**collection_id:** `str` — Unique identifier for a Collection
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Pages
+client.pages.list (...) -> PageList
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+List of all pages for a site.
+
+Required scope | `pages:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.pages.list(
+ site_id="580e63e98c9a982ac9b8b741",
+ locale_id="65427cf400e02b306eaa04a0",
+ limit=1,
+ offset=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**locale_id:** `typing.Optional[str]`
+
+Unique identifier for a specific Locale.
+
+[Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+
+
+
+
+
+
+**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
+
+
+
+
+
+
+
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.pages.get_metadata (...) -> Page
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Get metadata information for a single page.
+
+Required scope | `pages:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.pages.get_metadata(
+ page_id="63c720f9347c2139b248e552",
+ locale_id="65427cf400e02b306eaa04a0",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**page_id:** `str` — Unique identifier for a Page
+
+
+
+
+
+
+
+**locale_id:** `typing.Optional[str]`
+
+Unique identifier for a specific Locale.
+
+[Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.pages.update_page_settings (...) -> Page
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Update Page-level metadata, including SEO and Open Graph fields.
+
+Required scope | `pages:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+from webflow.pages import PageMetadataWriteSeo, PageMetadataWriteOpenGraph
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.pages.update_page_settings(
+ page_id="63c720f9347c2139b248e552",
+ locale_id="65427cf400e02b306eaa04a0",
+ title="Guide to the Galaxy",
+ slug="guide-to-the-galaxy",
+ seo=PageMetadataWriteSeo(
+ 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.",
+ ),
+ open_graph=PageMetadataWriteOpenGraph(
+ title="Explore the Cosmos with The Ultimate Guide",
+ title_copied=False,
+ description="Dive deep into the mysteries of the universe with your guide to everything galactic.",
+ description_copied=False,
+ ),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**page_id:** `str` — Unique identifier for a Page
+
+
+
+
+
+
+
+**locale_id:** `typing.Optional[str]`
+
+Unique identifier for a specific Locale.
+
+[Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+
+
+
+
+
+
+**title:** `typing.Optional[str]` — Title for the page
+
+
+
+
+
+
+
+**slug:** `typing.Optional[str]`
+
+Slug for the page.
+
+
+**Note:** Updating slugs in secondary locales is only supported in Advanced and Enterprise localization add-on plans.
+
+
+
+
+
+
+
+**seo:** `typing.Optional[PageMetadataWriteSeo]` — SEO-related fields for the Page
+
+
+
+
+
+
+
+**open_graph:** `typing.Optional[PageMetadataWriteOpenGraph]` — Open Graph fields for the Page
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.pages.get_content (...) -> Dom
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Get text and component instance content from a static page.
+
+Localization
+
+Required scope | `pages:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.pages.get_content(
+ page_id="63c720f9347c2139b248e552",
+ locale_id="65427cf400e02b306eaa04a0",
+ limit=1,
+ offset=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**page_id:** `str` — Unique identifier for a Page
+
+
+
+
+
+
+
+**locale_id:** `typing.Optional[str]`
+
+Unique identifier for a specific Locale.
+
+[Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+
+
+
+
+
+
+**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
+
+
+
+
+
+
+
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.pages.update_static_content (...) -> UpdateStaticContentResponse
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+This endpoint updates content on a static page in **secondary locales**. It supports updating up to 1000 nodes in a single request.
+
+Before making updates:
+1. Use the [get page content](/data/reference/pages-and-components/pages/get-content) endpoint to identify available content nodes and their types.
+2. If the page has component instances, retrieve the component's properties that you'll override using the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint.
+3. DOM elements may include a `data-w-id` attribute. This attribute is used by Webflow to maintain custom attributes and links across locales. Always include the original `data-w-id` value in your update requests to ensure consistent behavior across all locales.
+
+
+ This endpoint is specifically for localized pages. Ensure that the specified `localeId` is a valid **secondary locale** for the site otherwise the request will fail.
+
+
+Required scope | `pages:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow, TextNodeWrite
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.pages.update_static_content(
+ page_id="63c720f9347c2139b248e552",
+ locale_id="localeId",
+ nodes=[
+ TextNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad623",
+ text="The Hitchhiker\'s Guide to the Galaxy ",
+ ),
+ TextNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad627",
+ text="Don\'t Panic! Always know where your towel is.
",
+ ),
+ TextNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad635",
+ ),
+ TextNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad642",
+ ),
+ TextNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad671",
+ ),
+ TextNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad629",
+ )
+ ],
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**page_id:** `str` — Unique identifier for a Page
+
+
+
+
+
+
+
+**locale_id:** `str` — The locale identifier.
+
+
+
+
+
+
+
+**nodes:** `typing.List[PageDomWriteNodesItem]` — List of DOM Nodes with the new content that will be updated in each node.
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Components
+client.components.list (...) -> ComponentList
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+List of all components for a site.
+
+Required scope | `components:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.components.list(
+ site_id="580e63e98c9a982ac9b8b741",
+ branch_id="68026fa68ef6dc744c75b833",
+ limit=1,
+ offset=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**branch_id:** `typing.Optional[str]` — Scope the operation to work on a specific branch.
+
+
+
+
+
+
+
+**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
+
+
+
+
+
+
+
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.components.get_content (...) -> ComponentDom
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+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.
+
+Required scope | `components:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.components.get_content(
+ site_id="580e63e98c9a982ac9b8b741",
+ component_id="8505ba55-ef72-629e-f85c-33e4b703d48b",
+ locale_id="65427cf400e02b306eaa04a0",
+ branch_id="68026fa68ef6dc744c75b833",
+ limit=1,
+ offset=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**component_id:** `str` — Unique identifier for a Component
+
+
+
+
+
+
+
+**locale_id:** `typing.Optional[str]`
+
+Unique identifier for a specific Locale.
+
+[Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+
+
+
+
+
+
+**branch_id:** `typing.Optional[str]` — Scope the operation to work on a specific branch.
+
+
+
+
+
+
+
+**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
+
+
+
+
+
+
+
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.components.update_content (...) -> ComponentsUpdateContentResponse
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+This endpoint updates content within a component defintion for **secondary locales**. It supports updating up to 1000 nodes in a single request.
+
+Before making updates:
+1. Use the [get component content](/data/reference/pages-and-components/components/get-content) endpoint to identify available content nodes and their types.
+2. If your component definition has a component instance nested within it, retrieve the nested component instance's properties that you'll override using the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint.
+3. DOM elements may include a `data-w-id` attribute. This attribute is used by Webflow to maintain custom attributes and links across locales. Always include the original `data-w-id` value in your update requests to ensure consistent behavior across all locales.
+
+
+ This endpoint is specifically for localizing component definitions. Ensure that the specified `localeId` is a valid **secondary locale** for the site otherwise the request will fail.
+
+
+Required scope | `components:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow, TextNodeWrite
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.components.update_content(
+ site_id="580e63e98c9a982ac9b8b741",
+ component_id="8505ba55-ef72-629e-f85c-33e4b703d48b",
+ locale_id="65427cf400e02b306eaa04a0",
+ branch_id="68026fa68ef6dc744c75b833",
+ nodes=[
+ TextNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad623",
+ text="The Hitchhiker\'s Guide to the Galaxy ",
+ ),
+ TextNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad627",
+ text="Don\'t Panic! Always know where your towel is.
",
+ ),
+ TextNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad635",
+ ),
+ TextNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad642",
+ ),
+ TextNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad671",
+ ),
+ TextNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad629",
+ )
+ ],
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**component_id:** `str` — Unique identifier for a Component
+
+
+
+
+
+
+
+**nodes:** `typing.List[ComponentDomWriteNodesItem]` — List of DOM Nodes with the new content that will be updated in each node.
+
+
+
+
+
+
+
+**locale_id:** `typing.Optional[str]`
+
+Unique identifier for a specific Locale.
+
+[Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+
+
+
+
+
+
+**branch_id:** `typing.Optional[str]` — Scope the operation to work on a specific branch.
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.components.get_properties (...) -> ComponentProperties
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Get the default property values of a component definition.
+
+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`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.components.get_properties(
+ site_id="580e63e98c9a982ac9b8b741",
+ component_id="8505ba55-ef72-629e-f85c-33e4b703d48b",
+ locale_id="65427cf400e02b306eaa04a0",
+ branch_id="68026fa68ef6dc744c75b833",
+ limit=1,
+ offset=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**component_id:** `str` — Unique identifier for a Component
+
+
+
+
+
+
+
+**locale_id:** `typing.Optional[str]`
+
+Unique identifier for a specific Locale.
+
+[Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+
+
+
+
+
+
+**branch_id:** `typing.Optional[str]` — Scope the operation to work on a specific branch.
+
+
+
+
+
+
+
+**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
+
+
+
+
+
+
+
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.components.update_properties (...) -> ComponentsUpdatePropertiesResponse
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+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 properties that can be updated in a secondary locale.
+2. Rich Text properties may include a `data-w-id` attribute. This attribute is used by Webflow to maintain links across locales. Always include the original `data-w-id` value in your update requests to ensure consistent behavior across all locales.
+
+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`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+from webflow.components import ComponentPropertiesWritePropertiesItem
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.components.update_properties(
+ site_id="580e63e98c9a982ac9b8b741",
+ component_id="8505ba55-ef72-629e-f85c-33e4b703d48b",
+ locale_id="65427cf400e02b306eaa04a0",
+ branch_id="68026fa68ef6dc744c75b833",
+ properties=[
+ ComponentPropertiesWritePropertiesItem(
+ property_id="a245c12d-995b-55ee-5ec7-aa36a6cad623",
+ text="The Hitchhiker’s Guide to the Galaxy",
+ ),
+ ComponentPropertiesWritePropertiesItem(
+ property_id="a245c12d-995b-55ee-5ec7-aa36a6cad627",
+ text="Dont Panic! Always know where your towel is.
",
+ )
+ ],
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**component_id:** `str` — Unique identifier for a Component
+
+
+
+
+
+
+
+**properties:** `typing.List[ComponentPropertiesWritePropertiesItem]` — A list of component properties to update within the specified secondary locale.
+
+
+
+
+
+
+
+**locale_id:** `typing.Optional[str]`
+
+Unique identifier for a specific Locale.
+
+[Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+
+
+
+
+
+
+**branch_id:** `typing.Optional[str]` — Scope the operation to work on a specific branch.
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Scripts
+client.scripts.list (...) -> RegisteredScriptList
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Get a list of scripts that have been registered to a site. A site can have a maximum of 800 registered scripts.
+
+
+ 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
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.scripts.list(
+ site_id="580e63e98c9a982ac9b8b741",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.scripts.register_hosted (...) -> CustomCodeHostedResponse
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+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`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.scripts.register_hosted(
+ site_id="580e63e98c9a982ac9b8b741",
+ hosted_location="hostedLocation",
+ integrity_hash="integrityHash",
+ version="version",
+ display_name="displayName",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**hosted_location:** `str` — URI for an externally hosted script location
+
+
+
+
+
+
+
+**integrity_hash:** `str` — Sub-Resource Integrity Hash
+
+
+
+
+
+
+
+**version:** `str` — A Semantic Version (SemVer) string, denoting the version of the script
+
+
+
+
+
+
+
+**display_name:** `str` — User-facing name for the script. Must be between 1 and 50 alphanumeric characters
+
+
+
+
+
+
+
+**can_copy:** `typing.Optional[bool]` — Define whether the script can be copied on site duplication and transfer
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.scripts.register_inline (...) -> CustomCodeInlineResponse
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Register an inline script to a site. Inline scripts are limited to 2000 characters.
+
+
+ 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 Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.scripts.register_inline(
+ site_id="580e63e98c9a982ac9b8b741",
+ source_code="alert(\'hello world\');",
+ version="0.0.1",
+ display_name="Alert",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**source_code:** `str` — The code to be added to the site (to be hosted by Webflow).
+
+
+
+
+
+
+
+**version:** `str` — A Semantic Version (SemVer) string, denoting the version of the script
+
+
+
+
+
+
+
+**display_name:** `str` — User-facing name for the script. Must be between 1 and 50 alphanumeric characters
+
+
+
+
+
+
+
+**integrity_hash:** `typing.Optional[str]` — Sub-Resource Integrity Hash. Only required for externally hosted scripts (passed via hostedLocation)
+
+
+
+
+
+
+
+**can_copy:** `typing.Optional[bool]` — Define whether the script can be copied on site duplication and transfer
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Assets
+client.assets.list (...) -> Assets
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+List of assets uploaded to a site
+
+Required scope | `assets:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.assets.list(
+ site_id="580e63e98c9a982ac9b8b741",
+ offset=1,
+ limit=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
+
+
+
+
+
+
+
+**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.assets.create (...) -> AssetUpload
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+The first step in uploading an asset to a site.
+
+
+This endpoint generates a response with the following information: `uploadUrl` and `uploadDetails`.
+
+
+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`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.assets.create(
+ site_id="580e63e98c9a982ac9b8b741",
+ file_name="file.png",
+ file_hash="3c7d87c9575702bc3b1e991f4d3c638e",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**file_name:** `str` — File name including file extension. File names must be less than 100 characters.
+
+
+
+
+
+
+
+**file_hash:** `str` — MD5 hash of the file
+
+
+
+
+
+
+
+**parent_folder:** `typing.Optional[str]` — ID of the Asset folder (optional)
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.assets.get (...) -> Asset
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Get details about an asset
+
+Required scope | `assets:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.assets.get(
+ asset_id="580e63fc8c9a982ac9b8b745",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**asset_id:** `str` — Unique identifier for an Asset on a site
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.assets.delete (...)
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Delete an Asset
+
+Required Scope: `assets: write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.assets.delete(
+ asset_id="580e63fc8c9a982ac9b8b745",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**asset_id:** `str` — Unique identifier for an Asset on a site
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.assets.update (...) -> Asset
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Update details of an Asset.
+
+Required scope | `assets:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.assets.update(
+ asset_id="580e63fc8c9a982ac9b8b745",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**asset_id:** `str` — Unique identifier for an Asset on a site
+
+
+
+
+
+
+
+**locale_id:** `typing.Optional[str]` — Unique identifier for a specific locale. Applicable, when using localization.
+
+
+
+
+
+
+
+**display_name:** `typing.Optional[str]` — A human readable name for the asset
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.assets.list_folders (...) -> AssetFolderList
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+List Asset Folders within a given site
+
+Required scope | `assets:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.assets.list_folders(
+ site_id="580e63e98c9a982ac9b8b741",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.assets.create_folder (...) -> AssetFolder
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Create an Asset Folder within a given site
+
+Required scope | `assets:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.assets.create_folder(
+ site_id="580e63e98c9a982ac9b8b741",
+ display_name="my asset folder",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**display_name:** `str` — A human readable name for the Asset Folder
+
+
+
+
+
+
+
+**parent_folder:** `typing.Optional[str]` — An (optional) pointer to a parent Asset Folder (or null for root)
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.assets.get_folder (...) -> AssetFolder
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Get details about a specific Asset Folder
+
+Required scope | `assets:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.assets.get_folder(
+ asset_folder_id="6390c49774a71f0e3c1a08ee",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**asset_folder_id:** `str` — Unique identifier for an Asset Folder
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Webhooks
+client.webhooks.list (...) -> WebhookList
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+List all App-created Webhooks registered for a given site
+
+Required scope | `sites:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.webhooks.list(
+ site_id="580e63e98c9a982ac9b8b741",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.webhooks.create (...) -> Webhook
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Create a new Webhook.
+
+Limit of 75 registrations per `triggerType`, per site.
+
+Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients).
+Required scope | `sites:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+import datetime
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.webhooks.create(
+ site_id_="580e63e98c9a982ac9b8b741",
+ id="582266e0cd48de0f0e3c6d8b",
+ trigger_type="form_submission",
+ url="https://webhook.site/7f7f7f7f-7f7f-7f7f-7f7f-7f7f7f7f7f7f",
+ workspace_id="4f4e46fd476ea8c507000001",
+ site_id="562ac0395358780a1f5e6fbd",
+ last_triggered=datetime.datetime.fromisoformat("2023-02-08T23:59:28+00:00"),
+ created_on=datetime.datetime.fromisoformat("2022-11-08T23:59:28+00:00"),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**request:** `Webhook`
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.webhooks.get (...) -> Webhook
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Get a specific Webhook instance
+
+Required scope: `sites:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.webhooks.get(
+ webhook_id="580e64008c9a982ac9b8b754",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**webhook_id:** `str` — Unique identifier for a Webhook
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.webhooks.delete (...)
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Remove a Webhook
+
+Required scope: `sites:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.webhooks.delete(
+ webhook_id="580e64008c9a982ac9b8b754",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**webhook_id:** `str` — Unique identifier for a Webhook
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Forms
+client.forms.list (...) -> FormList
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+List forms for a given site.
+
+Required scope | `forms:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.forms.list(
+ site_id="580e63e98c9a982ac9b8b741",
+ limit=1,
+ offset=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
+
+
+
+
+
+
+
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.forms.get (...) -> Form
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Get information about a given form.
+
+Required scope | `forms:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.forms.get(
+ form_id="580e63e98c9a982ac9b8b741",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**form_id:** `str` — Unique identifier for a Form
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.forms.list_submissions (...) -> FormSubmissionList
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+List form submissions for a given form
+
+
+ When a form is used in a component definition, each instance of the form is considered a unique form.
+
+ To get a combined list of submissions for a form that appears across multiple component instances, use the [List Form Submissions by Site](/data/reference/forms/form-submissions/list-submissions-by-site) endpoint.
+
+
+Required scope | `forms:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.forms.list_submissions(
+ form_id="580e63e98c9a982ac9b8b741",
+ offset=1,
+ limit=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**form_id:** `str` — Unique identifier for a Form
+
+
+
+
+
+
+
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
+
+
+
+
+
+
+
+**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.forms.get_submission (...) -> FormSubmission
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Get information about a given form submissio.
+
+Required scope | `forms:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.forms.get_submission(
+ form_submission_id="580e63e98c9a982ac9b8b741",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**form_submission_id:** `str` — Unique identifier for a Form Submission
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.forms.delete_submission (...)
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Delete a form submission
+
+
+Required scope | `forms:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.forms.delete_submission(
+ form_submission_id="580e63e98c9a982ac9b8b741",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**form_submission_id:** `str` — Unique identifier for a Form Submission
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.forms.update_submission (...) -> FormSubmission
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Update hidden fields on a form submission
+
+Required scope | `forms:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.forms.update_submission(
+ form_submission_id="580e63e98c9a982ac9b8b741",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**form_submission_id:** `str` — Unique identifier for a Form Submission
+
+
+
+
+
+
+
+**form_submission_data:** `typing.Optional[typing.Dict[str, typing.Any]]` — An existing **hidden field** defined on the form schema, and the corresponding value to set
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Products
+client.products.list (...) -> ProductAndSkUsList
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Retrieve all products for a site.
+
+Use `limit` and `offset` to page through all products with subsequent requests. All SKUs for each product
+will also be fetched and returned. The `limit`, `offset` and `total` values represent Products only and do not include any SKUs.
+
+Required scope | `ecommerce:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.products.list(
+ site_id="580e63e98c9a982ac9b8b741",
+ offset=1,
+ limit=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
+
+
+
+
+
+
+
+**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.products.create (...) -> ProductAndSkUs
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Create a new ecommerce product and defaultSKU. A product, at minimum, must have a single SKU.
+
+To create a product with multiple SKUs:
+ - First, create a list of `sku-properties`, also known as [product options](https://help.webflow.com/hc/en-us/articles/33961334531347-Create-product-options-and-variants). For example, a T-shirt product may have a "color" `sku-property`, with a list of enum values: red, yellow, and blue, another `sku-property` may be "size", with a list of enum values: small, medium, and large.
+ - Once, a product is created with a list of `sku-properties`, Webflow will create a **default SKU**, which is always a combination of the first `enum` values of each `sku-property`. (e.g. Small - Red - T-Shirt)
+ - After creation, you can create additional SKUs for the product, using the [Create SKUs endpoint.](/data/reference/ecommerce/products/create-sku)
+
+Upon creation, the default product type will be `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer.
+
+Required scope | `ecommerce:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow, ProductFieldData, SkuPropertyList, SkuPropertyListEnumItem, SkuFieldData, SkuFieldDataPrice
+from webflow.environment import WebflowEnvironment
+from webflow.products import ProductSkuCreateProduct, ProductSkuCreateSku
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.products.create(
+ site_id="580e63e98c9a982ac9b8b741",
+ publish_status="staging",
+ product=ProductSkuCreateProduct(
+ field_data=ProductFieldData(
+ name="Colorful T-shirt",
+ slug="colorful-t-shirt",
+ description="Our best-selling t-shirt available in multiple colors and sizes",
+ sku_properties=[
+ SkuPropertyList(
+ id="color",
+ name="Color",
+ enum=[
+ SkuPropertyListEnumItem(
+ id="red",
+ name="Red",
+ slug="red",
+ ),
+ SkuPropertyListEnumItem(
+ id="yellow",
+ name="Yellow",
+ slug="yellow",
+ ),
+ SkuPropertyListEnumItem(
+ id="blue",
+ name="Blue",
+ slug="blue",
+ )
+ ],
+ ),
+ SkuPropertyList(
+ id="size",
+ name="Size",
+ enum=[
+ SkuPropertyListEnumItem(
+ id="small",
+ name="Small",
+ slug="small",
+ ),
+ SkuPropertyListEnumItem(
+ id="medium",
+ name="Medium",
+ slug="medium",
+ ),
+ SkuPropertyListEnumItem(
+ id="large",
+ name="Large",
+ slug="large",
+ )
+ ],
+ )
+ ],
+ ),
+ ),
+ sku=ProductSkuCreateSku(
+ field_data=SkuFieldData(
+ name="Colorful T-shirt - Red Small",
+ slug="colorful-t-shirt-red-small",
+ price=SkuFieldDataPrice(
+ value=2499,
+ unit="USD",
+ currency="USD",
+ ),
+ main_image="https://rocketamp-sample-store.myshopify.com/cdn/shop/products/Gildan_2000_Antique_Cherry_Red_Front_1024x1024.jpg?v=1527232987",
+ ),
+ ),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**product:** `ProductSkuCreateProduct`
+
+
+
+
+
+
+
+**sku:** `ProductSkuCreateSku`
+
+
+
+
+
+
+
+**publish_status:** `typing.Optional[PublishStatus]`
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.products.get (...) -> ProductAndSkUs
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Retrieve a single product by its ID. All of its SKUs will also be
+retrieved.
+
+Required scope | `ecommerce:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.products.get(
+ site_id="580e63e98c9a982ac9b8b741",
+ product_id="580e63fc8c9a982ac9b8b745",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**product_id:** `str` — Unique identifier for a Product
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.products.update (...) -> Product
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Update an existing Product.
+
+Updating an existing Product will set the product type to `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer.
+
+Required scope | `ecommerce:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.products.update(
+ site_id="580e63e98c9a982ac9b8b741",
+ product_id="580e63fc8c9a982ac9b8b745",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**product_id:** `str` — Unique identifier for a Product
+
+
+
+
+
+
+
+**publish_status:** `typing.Optional[PublishStatus]`
+
+
+
+
+
+
+
+**product:** `typing.Optional[Product]`
+
+
+
+
+
+
+
+**sku:** `typing.Optional[Sku]`
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.products.create_sku (...) -> ProductsCreateSkuResponse
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Create additional SKUs to manage every [option and variant of your Product.](https://help.webflow.com/hc/en-us/articles/33961334531347-Create-product-options-and-variants)
+
+Creating SKUs through the API will set the product type to `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer.
+
+Required scope | `ecommerce:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow, Sku, SkuFieldData, SkuFieldDataPrice
+from webflow.environment import WebflowEnvironment
+import datetime
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.products.create_sku(
+ site_id="580e63e98c9a982ac9b8b741",
+ product_id="580e63fc8c9a982ac9b8b745",
+ skus=[
+ Sku(
+ id="66072fb71b89448912e2681c",
+ cms_locale_id="653ad57de882f528b32e810e",
+ last_published=datetime.datetime.fromisoformat("2023-03-17T18:47:35+00:00"),
+ last_updated=datetime.datetime.fromisoformat("2023-03-17T18:47:35+00:00"),
+ created_on=datetime.datetime.fromisoformat("2023-03-17T18:47:35+00:00"),
+ field_data=SkuFieldData(
+ name="Colorful T-shirt - Default",
+ slug="colorful-t-shirt-default",
+ price=SkuFieldDataPrice(
+ value=2499,
+ unit="USD",
+ currency="USD",
+ ),
+ ),
+ )
+ ],
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**product_id:** `str` — Unique identifier for a Product
+
+
+
+
+
+
+
+**skus:** `typing.List[Sku]` — An array of the SKU data your are adding
+
+
+
+
+
+
+
+**publish_status:** `typing.Optional[PublishStatus]`
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.products.update_sku (...) -> Sku
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Update a specified SKU.
+
+Updating an existing SKU will set the Product type to `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer.
+
+Required scope | `ecommerce:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow, Sku, SkuFieldData, SkuFieldDataPrice
+from webflow.environment import WebflowEnvironment
+import datetime
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.products.update_sku(
+ site_id="580e63e98c9a982ac9b8b741",
+ product_id="580e63fc8c9a982ac9b8b745",
+ sku_id="5e8518516e147040726cc415",
+ sku=Sku(
+ id="66072fb71b89448912e2681c",
+ cms_locale_id="653ad57de882f528b32e810e",
+ last_published=datetime.datetime.fromisoformat("2023-03-17T18:47:35+00:00"),
+ last_updated=datetime.datetime.fromisoformat("2023-03-17T18:47:35+00:00"),
+ created_on=datetime.datetime.fromisoformat("2023-03-17T18:47:35+00:00"),
+ field_data=SkuFieldData(
+ name="Colorful T-shirt - Default",
+ slug="colorful-t-shirt-default",
+ price=SkuFieldDataPrice(
+ value=2499,
+ unit="USD",
+ currency="USD",
+ ),
+ ),
+ ),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**product_id:** `str` — Unique identifier for a Product
+
+
+
+
+
+
+
+**sku_id:** `str` — Unique identifier for a SKU
+
+
+
+
+
+
+
+**sku:** `Sku`
+
+
+
+
+
+
+
+**publish_status:** `typing.Optional[PublishStatus]`
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Orders
+client.orders.list (...) -> OrderList
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+List all orders created for a given site.
+
+Required scope | `ecommerce:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.orders.list(
+ site_id="580e63e98c9a982ac9b8b741",
+ status="pending",
+ offset=1,
+ limit=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**status:** `typing.Optional[OrdersListRequestStatus]` — Filter the orders by status
+
+
+
+
+
+
+
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
+
+
+
+
+
+
+
+**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.orders.get (...) -> Order
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Retrieve a single product by its ID. All of its SKUs will also be
+retrieved.
+
+Required scope | `ecommerce:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.orders.get(
+ site_id="580e63e98c9a982ac9b8b741",
+ order_id="5e8518516e147040726cc415",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**order_id:** `str` — Unique identifier for an Order
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.orders.update (...) -> Order
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+This API lets you update the fields, `comment`, `shippingProvider`,
+and/or `shippingTracking` for a given order. All three fields can be
+updated simultaneously or independently.
+
+Required scope | `ecommerce:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.orders.update(
+ site_id="580e63e98c9a982ac9b8b741",
+ order_id="5e8518516e147040726cc415",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**order_id:** `str` — Unique identifier for an Order
+
+
+
+
+
+
+
+**comment:** `typing.Optional[str]` — Arbitrary data for your records
+
+
+
+
+
+
+
+**shipping_provider:** `typing.Optional[str]` — Company or method used to ship order
+
+
+
+
+
+
+
+**shipping_tracking:** `typing.Optional[str]` — Tracking number for order shipment
+
+
+
+
+
+
+
+**shipping_tracking_url:** `typing.Optional[str]` — URL to track order shipment
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.orders.update_fulfill (...) -> Order
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Updates an order's status to fulfilled
+
+Required scope | `ecommerce:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.orders.update_fulfill(
+ site_id="580e63e98c9a982ac9b8b741",
+ order_id="5e8518516e147040726cc415",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**order_id:** `str` — Unique identifier for an Order
+
+
+
+
+
+
+
+**send_order_fulfilled_email:** `typing.Optional[bool]` — Whether or not the Order Fulfilled email should be sent
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.orders.update_unfulfill (...) -> Order
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Updates an order's status to unfulfilled
+
+Required scope | `ecommerce:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.orders.update_unfulfill(
+ site_id="580e63e98c9a982ac9b8b741",
+ order_id="5e8518516e147040726cc415",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**order_id:** `str` — Unique identifier for an Order
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.orders.refund (...) -> Order
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+This API will reverse a Stripe charge and refund an order back to a
+customer. It will also set the order's status to `refunded`.
+
+Required scope | `ecommerce:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.orders.refund(
+ site_id="580e63e98c9a982ac9b8b741",
+ order_id="5e8518516e147040726cc415",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**order_id:** `str` — Unique identifier for an Order
+
+
+
+
+
+
+
+**reason:** `typing.Optional[OrdersRefundRequestReason]` — The reason for the refund
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Inventory
+client.inventory.list (...) -> InventoryItem
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+List the current inventory levels for a particular SKU item.
+
+Required scope | `ecommerce:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.inventory.list(
+ sku_collection_id="6377a7c4b7a79608c34a46f7",
+ sku_id="5e8518516e147040726cc415",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**sku_collection_id:** `str` — Unique identifier for a SKU collection. Use the List Collections API to find this ID.
+
+
+
+
+
+
+
+**sku_id:** `str` — Unique identifier for a SKU
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.inventory.update (...) -> InventoryItem
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Updates the current inventory levels for a particular SKU item.
+
+Updates may be given in one or two methods, absolutely or incrementally.
+- Absolute updates are done by setting `quantity` directly.
+- Incremental updates are by specifying the inventory delta in `updateQuantity` which is then added to the `quantity` stored on the server.
+
+Required scope | `ecommerce:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.inventory.update(
+ sku_collection_id="6377a7c4b7a79608c34a46f7",
+ sku_id="5e8518516e147040726cc415",
+ inventory_type="infinite",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**sku_collection_id:** `str` — Unique identifier for a SKU collection. Use the List Collections API to find this ID.
+
+
+
+
+
+
+
+**sku_id:** `str` — Unique identifier for a SKU
+
+
+
+
+
+
+
+**inventory_type:** `InventoryUpdateRequestInventoryType` — infinite or finite
+
+
+
+
+
+
+
+**update_quantity:** `typing.Optional[float]` — Adds this quantity to currently store quantity. Can be negative.
+
+
+
+
+
+
+
+**quantity:** `typing.Optional[float]` — Immediately sets quantity to this value.
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Ecommerce
+client.ecommerce.get_settings (...) -> EcommerceSettings
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Retrieve ecommerce settings for a site.
+
+Required scope | `ecommerce:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.ecommerce.get_settings(
+ site_id="580e63e98c9a982ac9b8b741",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Collections Fields
+client.collections.fields.create (...) -> FieldCreate
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Create a custom field in a collection.
+
+Field validation is currently not available through the API.
+
+Bulk creation of fields is not supported with this endpoint. To add multiple fields at once, include them when you [create the collection.](/data/v2.0.0/reference/cms/collections/create)
+
+Required scope | `cms:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow, StaticField
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.fields.create(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ request=StaticField(
+ id="562ac0395358780a1f5e6fbc",
+ is_editable=True,
+ is_required=False,
+ type="RichText",
+ display_name="Post Body",
+ help_text="Add the body of your post here",
+ ),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**collection_id:** `str` — Unique identifier for a Collection
+
+
+
+
+
+
+
+**request:** `FieldCreate`
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.collections.fields.delete (...)
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Delete a custom field in a collection. This endpoint does not currently support bulk deletion.
+
+Required scope | `cms:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.fields.delete(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ field_id="580e63fc8c9a982ac9b8b745",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**collection_id:** `str` — Unique identifier for a Collection
+
+
+
+
+
+
+
+**field_id:** `str` — Unique identifier for a Field in a collection
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.collections.fields.update (...) -> Field
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Update a custom field in a collection.
+
+Required scope | `cms:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.fields.update(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ field_id="580e63fc8c9a982ac9b8b745",
+ is_required=False,
+ display_name="Post Body",
+ help_text="Add the body of your post here",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**collection_id:** `str` — Unique identifier for a Collection
+
+
+
+
+
+
+
+**field_id:** `str` — Unique identifier for a Field in a collection
+
+
+
+
+
+
+
+**is_required:** `typing.Optional[bool]` — Define whether a field is required in a collection
+
+
+
+
+
+
+
+**display_name:** `typing.Optional[str]` — The name of a field
+
+
+
+
+
+
+
+**help_text:** `typing.Optional[str]` — Additional text to help anyone filling out this field
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Collections Items
+client.collections.items.list_items (...) -> CollectionItemList
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+List of all Items within a Collection.
+
+Required scope | `CMS:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.items.list_items(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ cms_locale_id="cmsLocaleId",
+ offset=1,
+ limit=1,
+ name="name",
+ slug="slug",
+ sort_by="lastPublished",
+ sort_order="asc",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**collection_id:** `str` — Unique identifier for a Collection
+
+
+
+
+
+
+
+**cms_locale_id:** `typing.Optional[str]` — Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+
+
+
+
+
+
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
+
+
+
+
+
+
+
+**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
+
+
+
+
+
+
+
+**name:** `typing.Optional[str]` — Filter by the exact name of the item(s)
+
+
+
+
+
+
+
+**slug:** `typing.Optional[str]` — Filter by the exact slug of the item
+
+
+
+
+
+
+
+**last_published:** `typing.Optional[ItemsListItemsRequestLastPublished]` — Filter by the last published date of the item(s)
+
+
+
+
+
+
+
+**sort_by:** `typing.Optional[ItemsListItemsRequestSortBy]` — Sort results by the provided value
+
+
+
+
+
+
+
+**sort_order:** `typing.Optional[ItemsListItemsRequestSortOrder]` — Sorts the results by asc or desc
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.collections.items.create_item (...) -> CollectionItem
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Create Item(s) in a Collection.
+
+
+To create items across multiple locales, please use [this endpoint.](/data/reference/cms/collection-items/staged-items/create-items)
+
+Required scope | `CMS:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow, CollectionItemPostSingle, CollectionItemPostSingleFieldData
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.items.create_item(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ skip_invalid_files=True,
+ request=CollectionItemPostSingle(
+ is_archived=False,
+ is_draft=False,
+ field_data=CollectionItemPostSingleFieldData(
+ name="The Hitchhiker\'s Guide to the Galaxy",
+ slug="hitchhikers-guide-to-the-galaxy",
+ ),
+ ),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**collection_id:** `str` — Unique identifier for a Collection
+
+
+
+
+
+
+
+**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.
+
+
+
+
+
+
+
+
+
+
+
+client.collections.items.delete_items (...)
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Delete Items from a Collection.
+
+Items will only be deleted in the primary locale unless a `cmsLocaleId` is included in the request.
+
+Required scope | `CMS:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+from webflow.collections.items import ItemsDeleteItemsRequestItemsItem
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.items.delete_items(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ items=[
+ ItemsDeleteItemsRequestItemsItem(
+ id="580e64008c9a982ac9b8b754",
+ )
+ ],
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**collection_id:** `str` — Unique identifier for a Collection
+
+
+
+
+
+
+
+**items:** `typing.List[ItemsDeleteItemsRequestItemsItem]`
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.collections.items.update_items (...) -> ItemsUpdateItemsResponse
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Update a single item or multiple items in a Collection.
+
+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`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow, CollectionItemWithIdInput, CollectionItemWithIdInputFieldData
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.items.update_items(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ skip_invalid_files=True,
+ items=[
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5ea6",
+ cms_locale_id="66f6e966c9e1dc700a857ca5",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="Ne Paniquez Pas",
+ slug="ne-paniquez-pas",
+ ),
+ ),
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5ea6",
+ cms_locale_id="66f6e966c9e1dc700a857ca4",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="No Entrar en Pánico",
+ slug="no-entrar-en-panico",
+ ),
+ ),
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5eaa",
+ cms_locale_id="66f6e966c9e1dc700a857ca5",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="Au Revoir et Merci pour Tous les Poissons",
+ slug="au-revoir-et-merci",
+ ),
+ ),
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5eaa",
+ cms_locale_id="66f6e966c9e1dc700a857ca4",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="Hasta Luego y Gracias por Todo el Pescado",
+ slug="hasta-luego-y-gracias",
+ ),
+ )
+ ],
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**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.List[CollectionItemWithIdInput]]`
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.collections.items.list_items_live (...) -> CollectionItemList
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+List all published items in a collection.
+
+
+ Serving data to applications in real-time? Use the Content Delivery API at `api-cdn.webflow.com` for better performance. The CDN-backed endpoint is optimized for high-volume reads, while the Data API is designed for writes and management operations.
+
+
+Required scope | `CMS:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.items.list_items_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ cms_locale_id="cmsLocaleId",
+ offset=1,
+ limit=1,
+ name="name",
+ slug="slug",
+ sort_by="lastPublished",
+ sort_order="asc",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**collection_id:** `str` — Unique identifier for a Collection
+
+
+
+
+
+
+
+**cms_locale_id:** `typing.Optional[str]` — Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+
+
+
+
+
+
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
+
+
+
+
+
+
+
+**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
+
+
+
+
+
+
+
+**name:** `typing.Optional[str]` — Filter by the exact name of the item(s)
+
+
+
+
+
+
+
+**slug:** `typing.Optional[str]` — Filter by the exact slug of the item
+
+
+
+
+
+
+
+**last_published:** `typing.Optional[ItemsListItemsLiveRequestLastPublished]` — Filter by the last published date of the item(s)
+
+
+
+
+
+
+
+**sort_by:** `typing.Optional[ItemsListItemsLiveRequestSortBy]` — Sort results by the provided value
+
+
+
+
+
+
+
+**sort_order:** `typing.Optional[ItemsListItemsLiveRequestSortOrder]` — Sorts the results by asc or desc
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.collections.items.create_item_live (...) -> CollectionItem
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Create item(s) in a collection that will be immediately published to the live site.
+
+
+To create items across multiple locales, [please use this endpoint.](/data/reference/cms/collection-items/staged-items/create-items)
+
+
+Required scope | `CMS:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow, CollectionItem, CollectionItemFieldData
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.items.create_item_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ skip_invalid_files=True,
+ request=CollectionItem(
+ is_archived=False,
+ is_draft=False,
+ field_data=CollectionItemFieldData(
+ name="The Hitchhiker\'s Guide to the Galaxy",
+ slug="hitchhikers-guide-to-the-galaxy",
+ ),
+ ),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**collection_id:** `str` — Unique identifier for a Collection
+
+
+
+
+
+
+
+**request:** `ItemsCreateItemLiveRequestBody`
+
+
+
+
+
+
+
+**skip_invalid_files:** `typing.Optional[bool]` — When true, invalid files are skipped and processing continues. When false, the entire request fails if any file is invalid.
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.collections.items.delete_items_live (...)
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Unpublish up to 100 items from the live site and set the `isDraft` property to `true`.
+
+Items will only be unpublished in the primary locale unless a `cmsLocaleId` is included in the request.
+
+Required scope | `CMS:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+from webflow.collections.items import ItemsDeleteItemsLiveRequestItemsItem
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.items.delete_items_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ items=[
+ ItemsDeleteItemsLiveRequestItemsItem(
+ id="580e64008c9a982ac9b8b754",
+ )
+ ],
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**collection_id:** `str` — Unique identifier for a Collection
+
+
+
+
+
+
+
+**items:** `typing.List[ItemsDeleteItemsLiveRequestItemsItem]`
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.collections.items.update_items_live (...) -> CollectionItemListNoPagination
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Update a single published item or multiple published items (up to 100) in a Collection
+
+Items will only be updated in the primary locale, unless a `cmsLocaleId` is included in the request.
+
+Required scope | `CMS:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow, CollectionItemWithIdInput, CollectionItemWithIdInputFieldData
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.items.update_items_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ skip_invalid_files=True,
+ items=[
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5ea6",
+ cms_locale_id="66f6e966c9e1dc700a857ca5",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="Ne Paniquez Pas",
+ slug="ne-paniquez-pas",
+ ),
+ ),
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5ea6",
+ cms_locale_id="66f6e966c9e1dc700a857ca4",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="No Entrar en Pánico",
+ slug="no-entrar-en-panico",
+ ),
+ ),
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5eaa",
+ cms_locale_id="66f6e966c9e1dc700a857ca5",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="Au Revoir et Merci pour Tous les Poissons",
+ slug="au-revoir-et-merci",
+ ),
+ ),
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5eaa",
+ cms_locale_id="66f6e966c9e1dc700a857ca4",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="Hasta Luego y Gracias por Todo el Pescado",
+ slug="hasta-luego-y-gracias",
+ ),
+ )
+ ],
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**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.List[CollectionItemWithIdInput]]`
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.collections.items.create_items (...) -> BulkCollectionItem
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Create an item or multiple items in a CMS Collection across multiple corresponding locales.
+
+
+ - This endpoint can create up to 100 items in a request.
+ - If the `cmsLocaleIds` parameter is not included in the request, an item will only be created in the primary locale.
+
+
+Required scope | `CMS:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+from webflow.collections.items import SingleCmsItem
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.items.create_items(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ skip_invalid_files=True,
+ cms_locale_ids=[
+ "66f6e966c9e1dc700a857ca3",
+ "66f6e966c9e1dc700a857ca4",
+ "66f6e966c9e1dc700a857ca5"
+ ],
+ is_archived=False,
+ is_draft=False,
+ field_data=SingleCmsItem(
+ name="Don’t Panic",
+ slug="dont-panic",
+ ),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**collection_id:** `str` — Unique identifier for a Collection
+
+
+
+
+
+
+
+**field_data:** `CreateBulkCollectionItemRequestBodyFieldData`
+
+
+
+
+
+
+
+**skip_invalid_files:** `typing.Optional[bool]` — When true, invalid files are skipped and processing continues. When false, the entire request fails if any file is invalid.
+
+
+
+
+
+
+
+**cms_locale_ids:** `typing.Optional[typing.List[str]]` — Array of identifiers for the locales where the item will be created
+
+
+
+
+
+
+
+**is_archived:** `typing.Optional[bool]` — Indicates whether the item is archived.
+
+
+
+
+
+
+
+**is_draft:** `typing.Optional[bool]` — Indicates whether the item is in draft state.
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.collections.items.get_item (...) -> CollectionItem
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Get details of a selected Collection Item.
+
+Required scope | `CMS:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.items.get_item(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ item_id="580e64008c9a982ac9b8b754",
+ cms_locale_id="cmsLocaleId",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**collection_id:** `str` — Unique identifier for a Collection
+
+
+
+
+
+
+
+**item_id:** `str` — Unique identifier for an Item
+
+
+
+
+
+
+
+**cms_locale_id:** `typing.Optional[str]` — Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.collections.items.delete_item (...)
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Delete an item from a collection.
+
+Required scope | `CMS:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.items.delete_item(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ item_id="580e64008c9a982ac9b8b754",
+ cms_locale_id="cmsLocaleId",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**collection_id:** `str` — Unique identifier for a Collection
+
+
+
+
+
+
+
+**item_id:** `str` — Unique identifier for an Item
+
+
+
+
+
+
+
+**cms_locale_id:** `typing.Optional[str]` — Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.collections.items.update_item (...) -> CollectionItem
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Update a selected Item in a Collection.
+
+Required scope | `CMS:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow, CollectionItemPatchSingleFieldData
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.items.update_item(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ item_id="580e64008c9a982ac9b8b754",
+ skip_invalid_files=True,
+ is_archived=False,
+ is_draft=False,
+ field_data=CollectionItemPatchSingleFieldData(
+ name="The Hitchhiker\'s Guide to the Galaxy",
+ slug="hitchhikers-guide-to-the-galaxy",
+ ),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**collection_id:** `str` — Unique identifier for a Collection
+
+
+
+
+
+
+
+**item_id:** `str` — Unique identifier for an Item
+
+
+
+
+
+
+
+**request:** `CollectionItemPatchSingle`
+
+
+
+
+
+
+
+**skip_invalid_files:** `typing.Optional[bool]` — When true, invalid files are skipped and processing continues. When false, the entire request fails if any file is invalid.
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.collections.items.get_item_live (...) -> CollectionItem
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Get details of a selected Collection live Item.
+
+
+ Serving data to applications in real-time? Use the Content Delivery API at `api-cdn.webflow.com` for better performance. The CDN-backed endpoint is optimized for high-volume reads, while the Data API is designed for writes and management operations.
+
+
+Required scope | `CMS:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.items.get_item_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ item_id="580e64008c9a982ac9b8b754",
+ cms_locale_id="cmsLocaleId",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**collection_id:** `str` — Unique identifier for a Collection
+
+
+
+
+
+
+
+**item_id:** `str` — Unique identifier for an Item
+
+
+
+
+
+
+
+**cms_locale_id:** `typing.Optional[str]` — Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.collections.items.delete_item_live (...)
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Unpublish a live item from the site and set the `isDraft` property to `true`.
+
+For bulk unpublishing, please use [this endpoint.](/data/v2.0.0/reference/cms/collection-items/live-items/delete-items-live)
+
+Required scope | `CMS:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.items.delete_item_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ item_id="580e64008c9a982ac9b8b754",
+ cms_locale_id="cmsLocaleId",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**collection_id:** `str` — Unique identifier for a Collection
+
+
+
+
+
+
+
+**item_id:** `str` — Unique identifier for an Item
+
+
+
+
+
+
+
+**cms_locale_id:** `typing.Optional[str]` — Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.collections.items.update_item_live (...) -> CollectionItem
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Update a selected live Item in a Collection. The updates for this Item will be published to the live site.
+
+Required scope | `CMS:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow, CollectionItemPatchSingleFieldData
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.items.update_item_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ item_id="580e64008c9a982ac9b8b754",
+ skip_invalid_files=True,
+ is_archived=False,
+ is_draft=False,
+ field_data=CollectionItemPatchSingleFieldData(
+ name="The Hitchhiker\'s Guide to the Galaxy",
+ slug="hitchhikers-guide-to-the-galaxy",
+ ),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**collection_id:** `str` — Unique identifier for a Collection
+
+
+
+
+
+
+
+**item_id:** `str` — Unique identifier for an Item
+
+
+
+
+
+
+
+**request:** `CollectionItemPatchSingle`
+
+
+
+
+
+
+
+**skip_invalid_files:** `typing.Optional[bool]` — When true, invalid files are skipped and processing continues. When false, the entire request fails if any file is invalid.
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.collections.items.publish_item (...) -> ItemsPublishItemResponse
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Publish an item or multiple items.
+
+Required scope | `cms:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+from webflow.collections.items import ItemIDs
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.collections.items.publish_item(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ request=ItemIDs(
+ item_ids=[
+ "643fd856d66b6528195ee2ca",
+ "643fd856d66b6528195ee2cb",
+ "643fd856d66b6528195ee2cc"
+ ],
+ ),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**collection_id:** `str` — Unique identifier for a Collection
+
+
+
+
+
+
+
+**request:** `ItemsPublishItemRequest`
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Pages Scripts
+client.pages.scripts.get_custom_code (...) -> ScriptApplyList
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Get all scripts applied to a page.
+
+Required scope | `custom_code:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.pages.scripts.get_custom_code(
+ page_id="63c720f9347c2139b248e552",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**page_id:** `str` — Unique identifier for a Page
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.pages.scripts.upsert_custom_code (...) -> ScriptApplyList
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Apply registered scripts to a page. If you have multiple scripts your App needs to apply or maintain on a page, ensure they are always included in the request body for this endpoint. To remove individual scripts, simply call this endpoint without the script in the request body.
+
+
+ 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`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow, ScriptApply
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.pages.scripts.upsert_custom_code(
+ page_id="63c720f9347c2139b248e552",
+ scripts=[
+ ScriptApply(
+ id="cms_slider",
+ location="header",
+ version="1.0.0",
+ attributes={
+ "my-attribute": "some-value"
+ },
+ ),
+ ScriptApply(
+ id="alert",
+ location="header",
+ version="0.0.1",
+ )
+ ],
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**page_id:** `str` — Unique identifier for a Page
+
+
+
+
+
+
+
+**request:** `ScriptApplyList`
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.pages.scripts.delete_custom_code (...)
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Remove all scripts from a page applied by the App. This endpoint will not remove scripts from the site's registered scripts.
+
+To remove individual scripts applied by the App, use the [Add/Update Custom Code](/data/reference/custom-code/custom-code-pages/upsert-custom-code) endpoint.
+
+Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app).
+
+Required scope | `custom_code:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.pages.scripts.delete_custom_code(
+ page_id="63c720f9347c2139b248e552",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**page_id:** `str` — Unique identifier for a Page
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Sites Redirects
+client.sites.redirects.list (...) -> Redirects
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+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`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.redirects.list(
+ site_id="580e63e98c9a982ac9b8b741",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.sites.redirects.create (...) -> Redirect
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+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`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.redirects.create(
+ site_id="580e63e98c9a982ac9b8b741",
+ id="42e1a2b7aa1a13f768a0042a",
+ from_url="/mostly-harmless",
+ to_url="/earth",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**request:** `Redirect`
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.sites.redirects.delete (...) -> Redirects
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+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`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.redirects.delete(
+ site_id="580e63e98c9a982ac9b8b741",
+ redirect_id="66c4cb9a20cac35ed19500e6",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**redirect_id:** `str` — Unique identifier site redirect
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.sites.redirects.update (...) -> Redirect
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Update a 301 redirection rule from a site.
+
+This endpoint requires an Enterprise workspace.
+
+Required scope: `sites:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.redirects.update(
+ site_id="580e63e98c9a982ac9b8b741",
+ redirect_id="66c4cb9a20cac35ed19500e6",
+ id="42e1a2b7aa1a13f768a0042a",
+ from_url="/mostly-harmless",
+ to_url="/earth",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**redirect_id:** `str` — Unique identifier site redirect
+
+
+
+
+
+
+
+**request:** `Redirect`
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Sites Plans
+client.sites.plans.get_site_plan (...) -> SitePlan
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Get site plan details for the specified Site.
+
+This endpoint requires an Enterprise workspace.
+
+Required scope | `sites:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.plans.get_site_plan(
+ site_id="580e63e98c9a982ac9b8b741",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Sites RobotsTxt
+client.sites.robots_txt.get (...) -> Robots
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Retrieve the robots.txt configuration for various user agents.
+
+This endpoint requires an Enterprise workspace.
+
+Required scope: `site_config:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.robots_txt.get(
+ site_id="580e63e98c9a982ac9b8b741",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.sites.robots_txt.put (...) -> Robots
+
+
+
+#### 📝 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 Webflow, RobotsRulesItem
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+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
+
+
+
+
+
+
+
+**request:** `Robots`
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.sites.robots_txt.delete (...) -> Robots
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+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`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow, RobotsRulesItem
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.robots_txt.delete(
+ site_id="580e63e98c9a982ac9b8b741",
+ rules=[
+ RobotsRulesItem(
+ user_agent="*",
+ allows=[
+ "/public"
+ ],
+ disallows=[
+ "/bubbles"
+ ],
+ )
+ ],
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**request:** `Robots`
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.sites.robots_txt.patch (...) -> Robots
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Update the `robots.txt` configuration for various user agents.
+
+This endpoint requires an Enterprise workspace.
+
+Required scope | `site_config:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow, RobotsRulesItem
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+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",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**request:** `Robots`
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Sites WellKnown
+client.sites.well_known.put (...)
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+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`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.well_known.put(
+ site_id="580e63e98c9a982ac9b8b741",
+ file_name="apple-app-site-association.txt",
+ file_data="{\n \"applinks\": {\n \"apps\": [],\n \"details\": [\n {\n \"appID\": \"ABCDE12345.com.example.app\",\n \"paths\": [ \"/*\", \"/some/path/*\" ]\n }\n ]\n }\n}\n",
+ content_type="application/json",
+)
+
+```
+
+
+
+
+
+#### ⚙️ 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.
+
+
+
+
+
+
+
+
+
+
+
+client.sites.well_known.delete (...)
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Delete existing well-known files from a site.
+
+This endpoint requires an Enterprise workspace.
+
+Required scope: `site_config:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.well_known.delete(
+ site_id="580e63e98c9a982ac9b8b741",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**file_names:** `typing.Optional[typing.List[str]]` — A list of file names to delete
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Sites ActivityLogs
+client.sites.activity_logs.list (...) -> SiteActivityLogResponse
+
+
+
+#### 📝 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
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.activity_logs.list(
+ site_id="580e63e98c9a982ac9b8b741",
+ limit=1,
+ offset=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
+
+
+
+
+
+
+
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Sites Comments
+client.sites.comments.list_comment_threads (...) -> CommentThreadList
+
+
+
+#### 📝 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
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.comments.list_comment_threads(
+ site_id="580e63e98c9a982ac9b8b741",
+ locale_id="65427cf400e02b306eaa04a0",
+ offset=1,
+ limit=1,
+ sort_by="createdOn",
+ sort_order="asc",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**locale_id:** `typing.Optional[str]`
+
+Unique identifier for a specific Locale.
+
+[Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+
+
+
+
+
+
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
+
+
+
+
+
+
+
+**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
+
+
+
+
+
+
+
+**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 (...) -> CommentThread
+
+
+
+#### 📝 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
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.comments.get_comment_thread(
+ site_id="580e63e98c9a982ac9b8b741",
+ comment_thread_id="580e63e98c9a982ac9b8b741",
+ locale_id="65427cf400e02b306eaa04a0",
+ offset=1,
+ limit=1,
+ sort_by="createdOn",
+ sort_order="asc",
+)
+
+```
+
+
+
+
+
+#### ⚙️ 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.
+
+[Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+
+
+
+
+
+
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
+
+
+
+
+
+
+
+**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
+
+
+
+
+
+
+
+**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 (...) -> CommentReplyList
+
+
+
+#### 📝 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
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.comments.list_comment_replies(
+ site_id="580e63e98c9a982ac9b8b741",
+ comment_thread_id="580e63e98c9a982ac9b8b741",
+ locale_id="65427cf400e02b306eaa04a0",
+ offset=1,
+ limit=1,
+ sort_by="createdOn",
+ sort_order="asc",
+)
+
+```
+
+
+
+
+
+#### ⚙️ 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.
+
+[Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+
+
+
+
+
+
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
+
+
+
+
+
+
+
+**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
+
+
+
+
+
+
+
+**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 (...) -> ScriptApplyList
+
+
+
+#### 📝 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
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+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 (...) -> ScriptApplyList
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Apply registered scripts to a site. If you have multiple scripts your App needs to apply or maintain on a site, ensure they are always included in the request body for this endpoint. To remove individual scripts, simply call this endpoint without the script in the request body.
+
+
+ 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 Webflow, ScriptApply
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+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
+
+
+
+
+
+
+
+**request:** `ScriptApplyList`
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.sites.scripts.delete_custom_code (...)
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Remove all scripts from a site applied by the App. This endpoint will not remove scripts from the site's registered scripts.
+
+To remove individual scripts applied by the App, use the [Add/Update Custom Code](/data/reference/custom-code/custom-code-sites/upsert-custom-code) endpoint.
+
+Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app).
+
+Required scope | `custom_code:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+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 (...) -> ListCustomCodeBlocks
+
+
+
+#### 📝 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
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.scripts.list_custom_code_blocks(
+ site_id="580e63e98c9a982ac9b8b741",
+ offset=1,
+ limit=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
+
+
+
+
+
+
+
+**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Sites Forms
+client.sites.forms.list_submissions_by_site (...) -> FormSubmissionList
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+List all form submissions for a given site with the ability to filter submissions by a centralized `elementId`.
+
+Add `elementId` when you want to filter form submissions to a specific form in a site. You can get the `elementId` from the [List forms endpoint](/data/reference/forms/forms/list) (displayed as `formElementId` in the response).
+
+
+When a form is used in a Webflow component definition, each instance of the component will yield a unique form. Adding the `elementId` in this request ensures this API response includes all submissions from that core form, wherever that form is used in instantiated components.
+
+
+Use the [List Form Submissions endpoint](/data/reference/forms/form-submissions/list-submissions) to list form submissions for a given form ID.
+
+Required scope | `forms:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.forms.list_submissions_by_site(
+ site_id="580e63e98c9a982ac9b8b741",
+ element_id="18259716-3e5a-646a-5f41-5dc4b9405aa0",
+ offset=1,
+ limit=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**element_id:** `typing.Optional[str]` — Identifier for an element
+
+
+
+
+
+
+
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
+
+
+
+
+
+
+
+**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.sites.forms.list_submissions (...) -> FormSubmissionList
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+List form submissions for a given form ID within a specific site.
+
+Use the [List Form Submissions by Site endpoint](/data/reference/forms/form-submissions/list-submissions-by-site) to list form submissions for a given site with the ability to filter by a `formElementId`.
+
+Required scope | `forms:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.forms.list_submissions(
+ site_id="580e63e98c9a982ac9b8b741",
+ form_id="580e63e98c9a982ac9b8b741",
+ offset=1,
+ limit=1,
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**form_id:** `str` — Unique identifier for a Form
+
+
+
+
+
+
+
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
+
+
+
+
+
+
+
+**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.sites.forms.get_submission (...) -> FormSubmission
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Get information about a form submission within a specific site.
+
+Required scope | `forms:read`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.forms.get_submission(
+ site_id="580e63e98c9a982ac9b8b741",
+ form_submission_id="580e63e98c9a982ac9b8b741",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**form_submission_id:** `str` — Unique identifier for a Form Submission
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.sites.forms.delete_submission (...)
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Delete a form submission within a specific site.
+
+Required scope | `forms:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.forms.delete_submission(
+ site_id="580e63e98c9a982ac9b8b741",
+ form_submission_id="580e63e98c9a982ac9b8b741",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**form_submission_id:** `str` — Unique identifier for a Form Submission
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.sites.forms.update_submission (...) -> FormSubmission
+
+
+
+#### 📝 Description
+
+
+
+
+
+
+
+Update hidden fields on a form submission within a specific site.
+
+Required scope | `forms:write`
+
+
+
+
+
+#### 🔌 Usage
+
+
+
+
+
+
+
+```python
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.sites.forms.update_submission(
+ site_id="580e63e98c9a982ac9b8b741",
+ form_submission_id="580e63e98c9a982ac9b8b741",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**site_id:** `str` — Unique identifier for a Site
+
+
+
+
+
+
+
+**form_submission_id:** `str` — Unique identifier for a Form Submission
+
+
+
+
+
+
+
+**form_submission_data:** `typing.Optional[typing.Dict[str, typing.Any]]` — An existing **hidden field** defined on the form schema, and the corresponding value to set
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## Workspaces AuditLogs
+client.workspaces.audit_logs.get_workspace_audit_logs (...) -> WorkspaceAuditLogResponse
+
+
+
+#### 📝 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
+from webflow import Webflow
+from webflow.environment import WebflowEnvironment
+import datetime
+
+client = Webflow(
+ access_token="",
+ environment=WebflowEnvironment.DATA_API,
+)
+
+client.workspaces.audit_logs.get_workspace_audit_logs(
+ workspace_id_or_slug="hitchhikers-workspace",
+ limit=1,
+ offset=1,
+ sort_order="asc",
+ event_type="user_access",
+ from_=datetime.datetime.fromisoformat("2025-06-22T16:00:31+00:00"),
+ to=datetime.datetime.fromisoformat("2025-07-22T16:00:31+00:00"),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+
+
+
+
+
+**workspace_id_or_slug:** `str` — Unique identifier or slug for a Workspace
+
+
+
+
+
+
+
+**limit:** `typing.Optional[int]` — Maximum number of records to be returned (max limit: 100)
+
+
+
+
+
+
+
+**offset:** `typing.Optional[int]` — Offset used for pagination if the results have more than limit records
+
+
+
+
+
+
+
+**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[datetime.datetime]` — The start date to filter by
+
+
+
+
+
+
+
+**to:** `typing.Optional[datetime.datetime]` — The end date to filter by
+
+
+
+
+
+
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..e80f640
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,4 @@
+httpx>=0.21.2
+pydantic>= 1.9.2
+pydantic-core>=2.18.2
+typing_extensions>= 4.0.0
diff --git a/src/webflow/__init__.py b/src/webflow/__init__.py
index 7d4de99..48d0673 100644
--- a/src/webflow/__init__.py
+++ b/src/webflow/__init__.py
@@ -1,176 +1,658 @@
# This file was auto-generated by Fern from our API Definition.
-from .types import (
- AccessGroup,
- AccessGroupList,
- Application,
- Asset,
- AssetFolder,
- AssetFolderList,
- AssetUpload,
- AssetUploadUploadDetails,
- AssetVariant,
- Assets,
- Authorization,
- AuthorizationAuthorization,
- AuthorizationAuthorizationAuthorizedTo,
- AuthorizedUser,
- Collection,
- CollectionItem,
- CollectionItemFieldData,
- CollectionItemList,
- CollectionItemListPagination,
- CollectionList,
- CollectionListArrayItem,
- CustomCodeBlock,
- CustomCodeBlockType,
- CustomCodeResponse,
- Dom,
- Domain,
- Domains,
- DuplicateUserEmail,
- EcommerceSettings,
- Error,
- ErrorDetailsItem,
- Field,
- FieldType,
- Form,
- FormField,
- FormFieldValue,
- FormFieldValueType,
- FormList,
- FormResponseSettings,
- FormSubmission,
- FormSubmissionList,
- ImageNode,
- InvalidDomain,
- InventoryItem,
- InventoryItemInventoryType,
- ListCustomCodeBlocks,
- MissingScopes,
- NoDomains,
- Node,
- NodeType,
- NotEnterprisePlanSite,
- OauthScope,
- Order,
- OrderAddress,
- OrderAddressJapanType,
- OrderAddressType,
- OrderCustomerInfo,
- OrderDisputeLastStatus,
- OrderDownloadFilesItem,
- OrderList,
- OrderMetadata,
- OrderPrice,
- OrderPurchasedItem,
- OrderPurchasedItemVariantImage,
- OrderPurchasedItemVariantImageFile,
- OrderPurchasedItemVariantImageFileVariantsItem,
- OrderStatus,
- OrderTotals,
- OrderTotalsExtrasItem,
- OrderTotalsExtrasItemType,
- Page,
- PageList,
- PageOpenGraph,
- PageSeo,
- Pagination,
- PaypalDetails,
- Product,
- ProductAndSkUs,
- ProductAndSkUsList,
- ProductFieldData,
- ProductFieldDataEcProductType,
- ProductFieldDataTaxCategory,
- PublishStatus,
- RegisteredScriptList,
- ScriptApply,
- ScriptApplyList,
- ScriptApplyLocation,
- Scripts,
- Site,
- SiteActivityLogItem,
- SiteActivityLogItemResourceOperation,
- SiteActivityLogItemUser,
- SiteActivityLogResponse,
- Sku,
- SkuFieldData,
- SkuFieldDataCompareAtPrice,
- SkuFieldDataEcSkuBillingMethod,
- SkuFieldDataEcSkuSubscriptionPlan,
- SkuFieldDataEcSkuSubscriptionPlanInterval,
- SkuFieldDataPrice,
- SkuPropertyList,
- SkuPropertyListEnumItem,
- SkuValueList,
- StripeCard,
- StripeCardBrand,
- StripeCardExpires,
- StripeDetails,
- TextNode,
- TriggerType,
- User,
- UserAccessGroupsItem,
- UserAccessGroupsItemType,
- UserData,
- UserDataData,
- UserLimitReached,
- UserList,
- UserStatus,
- UsersNotEnabled,
- Webhook,
- WebhookList,
-)
-from .errors import (
- BadRequestError,
- ConflictError,
- ForbiddenError,
- InternalServerError,
- NotFoundError,
- TooManyRequestsError,
- UnauthorizedError,
-)
-from .resources import (
- AccessGroupsListRequestSort,
- DomWriteNodesItem,
- InventoryUpdateRequestInventoryType,
- OrdersRefundRequestReason,
- ProductSkuCreateProduct,
- ProductSkuCreateProductFieldData,
- ProductSkuCreateProductFieldDataEcProductType,
- ProductSkuCreateProductFieldDataTaxCategory,
- ProductSkuCreateSku,
- ProductSkuCreateSkuFieldData,
- ProductSkuCreateSkuFieldDataCompareAtPrice,
- ProductSkuCreateSkuFieldDataEcSkuBillingMethod,
- ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlan,
- ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlanInterval,
- ProductSkuCreateSkuFieldDataPrice,
- ProductsCreateSkuResponse,
- UsersListRequestSort,
- UsersUpdateRequestData,
- access_groups,
- assets,
- collections,
- ecommerce,
- forms,
- inventory,
- orders,
- pages,
- products,
- scripts,
- sites,
- token,
- users,
- webhooks,
-)
-from .environment import WebflowEnvironment
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .types import (
+ Application,
+ Asset,
+ AssetFolder,
+ AssetFolderList,
+ AssetUpload,
+ AssetUploadUploadDetails,
+ AssetVariant,
+ Assets,
+ Authorization,
+ AuthorizationAuthorization,
+ AuthorizationAuthorizationAuthorizedTo,
+ AuthorizedUser,
+ BadRequestErrorBody,
+ BulkCollectionItem,
+ BulkCollectionItemFieldData,
+ Collection,
+ CollectionItem,
+ CollectionItemChanged,
+ CollectionItemCreated,
+ CollectionItemFieldData,
+ CollectionItemList,
+ CollectionItemListNoPagination,
+ CollectionItemListPagination,
+ CollectionItemPatchSingle,
+ CollectionItemPatchSingleFieldData,
+ CollectionItemPostSingle,
+ CollectionItemPostSingleFieldData,
+ CollectionItemPublished,
+ CollectionItemRemoved,
+ CollectionItemRemovedPayload,
+ CollectionItemRemovedPayloadFieldData,
+ CollectionItemUnpublished,
+ CollectionItemUnpublishedPayload,
+ CollectionItemUnpublishedPayloadFieldData,
+ CollectionItemWithIdInput,
+ CollectionItemWithIdInputFieldData,
+ CollectionList,
+ CollectionListArrayItem,
+ Comment,
+ CommentPayload,
+ CommentPayloadAuthor,
+ CommentPayloadMentionedUsersItem,
+ CommentReply,
+ CommentReplyAuthor,
+ CommentReplyList,
+ CommentReplyListPagination,
+ CommentReplyMentionedUsersItem,
+ CommentThread,
+ CommentThreadAuthor,
+ CommentThreadList,
+ CommentThreadListPagination,
+ CommentThreadMentionedUsersItem,
+ Component,
+ ComponentDom,
+ ComponentInstanceNodePropertyOverridesWrite,
+ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem,
+ ComponentList,
+ ComponentNode,
+ ComponentProperties,
+ ComponentProperty,
+ ComponentPropertyType,
+ Conflict,
+ CustomCodeBlock,
+ CustomCodeBlockType,
+ CustomCodeHostedResponse,
+ CustomCodeInlineResponse,
+ CustomRole,
+ CustomRoleAuditLogItem,
+ CustomRoleAuditLogItemEventSubType,
+ Dom,
+ Domain,
+ Domains,
+ EcommerceSettings,
+ Error,
+ ErrorCode,
+ Field,
+ FieldCreate,
+ FieldType,
+ FieldValidations,
+ FieldValidationsAdditionalProperties,
+ FieldValidationsAdditionalPropertiesAdditionalProperties,
+ ForbiddenErrorBody,
+ Form,
+ FormField,
+ FormFieldValue,
+ FormFieldValueType,
+ FormList,
+ FormResponseSettings,
+ FormSubmission,
+ FormSubmissionList,
+ FormSubmissionTrigger,
+ FormSubmissionTriggerPayload,
+ FormSubmissionTriggerPayloadSchemaItem,
+ FormSubmissionTriggerPayloadSchemaItemFieldType,
+ ImageNode,
+ ImageNodeImage,
+ InvalidDomain,
+ InvalidScopes,
+ InventoryItem,
+ InventoryItemInventoryType,
+ ItemsListItemsLiveRequestLastPublished,
+ ItemsListItemsRequestLastPublished,
+ ListCustomCodeBlocks,
+ Locale,
+ Locales,
+ Metadata,
+ MetadataOptionsItem,
+ NewOrder,
+ 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,
+ OrderList,
+ OrderMetadata,
+ OrderPrice,
+ OrderPurchasedItem,
+ OrderPurchasedItemVariantImage,
+ OrderPurchasedItemVariantImageFile,
+ OrderPurchasedItemVariantImageFileVariantsItem,
+ OrderShippingAddress,
+ OrderShippingAddressJapanType,
+ OrderShippingAddressType,
+ OrderStatus,
+ OrderTotals,
+ OrderTotalsExtrasItem,
+ OrderTotalsExtrasItemType,
+ Page,
+ PageCreatedWebhook,
+ PageCreatedWebhookPayload,
+ PageDeletedWebhook,
+ PageDeletedWebhookPayload,
+ PageList,
+ PageMetadataUpdatedWebhook,
+ PageMetadataUpdatedWebhookPayload,
+ PageOpenGraph,
+ PageSeo,
+ Pagination,
+ Payload,
+ PayloadFieldData,
+ PaypalDetails,
+ Product,
+ ProductAndSkUs,
+ ProductAndSkUsList,
+ ProductFieldData,
+ ProductFieldDataEcProductType,
+ ProductFieldDataTaxCategory,
+ PublishStatus,
+ Redirect,
+ Redirects,
+ ReferenceField,
+ ReferenceFieldMetadata,
+ ReferenceFieldType,
+ RegisteredScriptList,
+ Robots,
+ RobotsRulesItem,
+ ScriptApply,
+ ScriptApplyList,
+ ScriptApplyLocation,
+ Scripts,
+ SearchButtonNode,
+ SearchButtonNodeWrite,
+ Select,
+ SelectNode,
+ SelectNodeChoicesItem,
+ SelectNodeWriteChoicesItem,
+ SettingChange,
+ SettingChangeAuditLogItem,
+ SingleLocaleCreatedPayload,
+ SingleLocaleCreatedPayloadFieldData,
+ Site,
+ SiteActivityLogItem,
+ SiteActivityLogItemEvent,
+ SiteActivityLogItemResourceOperation,
+ SiteActivityLogItemUser,
+ SiteActivityLogResponse,
+ SiteDataCollectionType,
+ SiteMembership,
+ SiteMembershipAuditLogItem,
+ SiteMembershipAuditLogItemEventSubType,
+ SitePlan,
+ SitePlanId,
+ SitePlanName,
+ SitePublish,
+ SitePublishPayload,
+ Sites,
+ Sku,
+ SkuFieldData,
+ SkuFieldDataCompareAtPrice,
+ SkuFieldDataEcSkuBillingMethod,
+ SkuFieldDataEcSkuSubscriptionPlan,
+ SkuFieldDataEcSkuSubscriptionPlanInterval,
+ SkuFieldDataEcSkuSubscriptionPlanPlansItem,
+ SkuFieldDataEcSkuSubscriptionPlanPlansItemStatus,
+ SkuFieldDataPrice,
+ SkuPropertyList,
+ SkuPropertyListEnumItem,
+ SkuValueList,
+ StaticField,
+ StaticFieldType,
+ StripeCard,
+ StripeCardBrand,
+ StripeCardExpires,
+ StripeDetails,
+ SubmitButtonNode,
+ SubmitButtonNodeWrite,
+ Text,
+ TextInputNode,
+ TextInputNodeWrite,
+ TextNode,
+ TextNodeText,
+ TextNodeWrite,
+ TriggerType,
+ UpdatedOrder,
+ UserAccess,
+ UserAccessAuditLogItem,
+ UserAccessAuditLogItemEventSubType,
+ Webhook,
+ WebhookFilter,
+ WebhookList,
+ WorkspaceAuditLogItem,
+ WorkspaceAuditLogItemActor,
+ WorkspaceAuditLogItemPayloadSettingChangeMethod,
+ WorkspaceAuditLogItemPayloadSiteMembershipGranularAccess,
+ WorkspaceAuditLogItemPayloadSiteMembershipMethod,
+ WorkspaceAuditLogItemPayloadSiteMembershipSite,
+ WorkspaceAuditLogItemPayloadSiteMembershipTargetUser,
+ WorkspaceAuditLogItemPayloadSiteMembershipUserType,
+ WorkspaceAuditLogItemPayloadUserAccessMethod,
+ WorkspaceAuditLogItemPayloadWorkspaceInvitationMethod,
+ WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUser,
+ WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUsersItem,
+ WorkspaceAuditLogItemPayloadWorkspaceInvitationUserType,
+ WorkspaceAuditLogItemPayloadWorkspaceMembershipMethod,
+ WorkspaceAuditLogItemPayloadWorkspaceMembershipTargetUser,
+ WorkspaceAuditLogItemPayloadWorkspaceMembershipUserType,
+ WorkspaceAuditLogItemWorkspace,
+ WorkspaceAuditLogItem_CustomRole,
+ WorkspaceAuditLogItem_SiteMembership,
+ WorkspaceAuditLogItem_UserAccess,
+ WorkspaceAuditLogItem_WorkspaceInvitation,
+ WorkspaceAuditLogItem_WorkspaceMembership,
+ WorkspaceAuditLogItem_WorkspaceSetting,
+ WorkspaceAuditLogResponse,
+ WorkspaceInvitation,
+ WorkspaceInvitationAuditLogItem,
+ WorkspaceInvitationAuditLogItemEventSubType,
+ WorkspaceMembership,
+ WorkspaceMembershipAuditLogItem,
+ WorkspaceMembershipAuditLogItemEventSubType,
+ )
+ from .errors import (
+ BadRequestError,
+ ConflictError,
+ ForbiddenError,
+ InternalServerError,
+ NotFoundError,
+ TooManyRequestsError,
+ UnauthorizedError,
+ )
+ from .resources import (
+ ComponentDomWriteNodesItem,
+ ComponentPropertiesWritePropertiesItem,
+ ComponentsUpdateContentResponse,
+ ComponentsUpdatePropertiesResponse,
+ EcommInventoryChangedPayload,
+ InventoryUpdateRequestInventoryType,
+ OrdersListRequestStatus,
+ OrdersRefundRequestReason,
+ PageDomWriteNodesItem,
+ PageMetadataWriteOpenGraph,
+ PageMetadataWriteSeo,
+ ProductSkuCreateProduct,
+ ProductSkuCreateSku,
+ ProductsCreateSkuResponse,
+ SitesPublishResponse,
+ UpdateStaticContentResponse,
+ assets,
+ collections,
+ components,
+ ecommerce,
+ forms,
+ inventory,
+ orders,
+ pages,
+ products,
+ scripts,
+ sites,
+ token,
+ webhooks,
+ workspaces,
+ )
+ from .client import AsyncWebflow, Webflow
+ from .environment import WebflowEnvironment
+ from .version import __version__
+_dynamic_imports: typing.Dict[str, str] = {
+ "Application": ".types",
+ "Asset": ".types",
+ "AssetFolder": ".types",
+ "AssetFolderList": ".types",
+ "AssetUpload": ".types",
+ "AssetUploadUploadDetails": ".types",
+ "AssetVariant": ".types",
+ "Assets": ".types",
+ "AsyncWebflow": ".client",
+ "Authorization": ".types",
+ "AuthorizationAuthorization": ".types",
+ "AuthorizationAuthorizationAuthorizedTo": ".types",
+ "AuthorizedUser": ".types",
+ "BadRequestError": ".errors",
+ "BadRequestErrorBody": ".types",
+ "BulkCollectionItem": ".types",
+ "BulkCollectionItemFieldData": ".types",
+ "Collection": ".types",
+ "CollectionItem": ".types",
+ "CollectionItemChanged": ".types",
+ "CollectionItemCreated": ".types",
+ "CollectionItemFieldData": ".types",
+ "CollectionItemList": ".types",
+ "CollectionItemListNoPagination": ".types",
+ "CollectionItemListPagination": ".types",
+ "CollectionItemPatchSingle": ".types",
+ "CollectionItemPatchSingleFieldData": ".types",
+ "CollectionItemPostSingle": ".types",
+ "CollectionItemPostSingleFieldData": ".types",
+ "CollectionItemPublished": ".types",
+ "CollectionItemRemoved": ".types",
+ "CollectionItemRemovedPayload": ".types",
+ "CollectionItemRemovedPayloadFieldData": ".types",
+ "CollectionItemUnpublished": ".types",
+ "CollectionItemUnpublishedPayload": ".types",
+ "CollectionItemUnpublishedPayloadFieldData": ".types",
+ "CollectionItemWithIdInput": ".types",
+ "CollectionItemWithIdInputFieldData": ".types",
+ "CollectionList": ".types",
+ "CollectionListArrayItem": ".types",
+ "Comment": ".types",
+ "CommentPayload": ".types",
+ "CommentPayloadAuthor": ".types",
+ "CommentPayloadMentionedUsersItem": ".types",
+ "CommentReply": ".types",
+ "CommentReplyAuthor": ".types",
+ "CommentReplyList": ".types",
+ "CommentReplyListPagination": ".types",
+ "CommentReplyMentionedUsersItem": ".types",
+ "CommentThread": ".types",
+ "CommentThreadAuthor": ".types",
+ "CommentThreadList": ".types",
+ "CommentThreadListPagination": ".types",
+ "CommentThreadMentionedUsersItem": ".types",
+ "Component": ".types",
+ "ComponentDom": ".types",
+ "ComponentDomWriteNodesItem": ".resources",
+ "ComponentInstanceNodePropertyOverridesWrite": ".types",
+ "ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem": ".types",
+ "ComponentList": ".types",
+ "ComponentNode": ".types",
+ "ComponentProperties": ".types",
+ "ComponentPropertiesWritePropertiesItem": ".resources",
+ "ComponentProperty": ".types",
+ "ComponentPropertyType": ".types",
+ "ComponentsUpdateContentResponse": ".resources",
+ "ComponentsUpdatePropertiesResponse": ".resources",
+ "Conflict": ".types",
+ "ConflictError": ".errors",
+ "CustomCodeBlock": ".types",
+ "CustomCodeBlockType": ".types",
+ "CustomCodeHostedResponse": ".types",
+ "CustomCodeInlineResponse": ".types",
+ "CustomRole": ".types",
+ "CustomRoleAuditLogItem": ".types",
+ "CustomRoleAuditLogItemEventSubType": ".types",
+ "Dom": ".types",
+ "Domain": ".types",
+ "Domains": ".types",
+ "EcommInventoryChangedPayload": ".resources",
+ "EcommerceSettings": ".types",
+ "Error": ".types",
+ "ErrorCode": ".types",
+ "Field": ".types",
+ "FieldCreate": ".types",
+ "FieldType": ".types",
+ "FieldValidations": ".types",
+ "FieldValidationsAdditionalProperties": ".types",
+ "FieldValidationsAdditionalPropertiesAdditionalProperties": ".types",
+ "ForbiddenError": ".errors",
+ "ForbiddenErrorBody": ".types",
+ "Form": ".types",
+ "FormField": ".types",
+ "FormFieldValue": ".types",
+ "FormFieldValueType": ".types",
+ "FormList": ".types",
+ "FormResponseSettings": ".types",
+ "FormSubmission": ".types",
+ "FormSubmissionList": ".types",
+ "FormSubmissionTrigger": ".types",
+ "FormSubmissionTriggerPayload": ".types",
+ "FormSubmissionTriggerPayloadSchemaItem": ".types",
+ "FormSubmissionTriggerPayloadSchemaItemFieldType": ".types",
+ "ImageNode": ".types",
+ "ImageNodeImage": ".types",
+ "InternalServerError": ".errors",
+ "InvalidDomain": ".types",
+ "InvalidScopes": ".types",
+ "InventoryItem": ".types",
+ "InventoryItemInventoryType": ".types",
+ "InventoryUpdateRequestInventoryType": ".resources",
+ "ItemsListItemsLiveRequestLastPublished": ".types",
+ "ItemsListItemsRequestLastPublished": ".types",
+ "ListCustomCodeBlocks": ".types",
+ "Locale": ".types",
+ "Locales": ".types",
+ "Metadata": ".types",
+ "MetadataOptionsItem": ".types",
+ "NewOrder": ".types",
+ "NoDomains": ".types",
+ "Node": ".types",
+ "Node_ComponentInstance": ".types",
+ "Node_Image": ".types",
+ "Node_SearchButton": ".types",
+ "Node_Select": ".types",
+ "Node_SubmitButton": ".types",
+ "Node_Text": ".types",
+ "Node_TextInput": ".types",
+ "NotEnterprisePlanSite": ".types",
+ "NotEnterprisePlanWorkspace": ".types",
+ "NotFoundError": ".errors",
+ "OptionField": ".types",
+ "Order": ".types",
+ "OrderAddress": ".types",
+ "OrderAddressJapanType": ".types",
+ "OrderAddressType": ".types",
+ "OrderBillingAddress": ".types",
+ "OrderBillingAddressJapanType": ".types",
+ "OrderBillingAddressType": ".types",
+ "OrderCustomerInfo": ".types",
+ "OrderDisputeLastStatus": ".types",
+ "OrderDownloadFilesItem": ".types",
+ "OrderList": ".types",
+ "OrderMetadata": ".types",
+ "OrderPrice": ".types",
+ "OrderPurchasedItem": ".types",
+ "OrderPurchasedItemVariantImage": ".types",
+ "OrderPurchasedItemVariantImageFile": ".types",
+ "OrderPurchasedItemVariantImageFileVariantsItem": ".types",
+ "OrderShippingAddress": ".types",
+ "OrderShippingAddressJapanType": ".types",
+ "OrderShippingAddressType": ".types",
+ "OrderStatus": ".types",
+ "OrderTotals": ".types",
+ "OrderTotalsExtrasItem": ".types",
+ "OrderTotalsExtrasItemType": ".types",
+ "OrdersListRequestStatus": ".resources",
+ "OrdersRefundRequestReason": ".resources",
+ "Page": ".types",
+ "PageCreatedWebhook": ".types",
+ "PageCreatedWebhookPayload": ".types",
+ "PageDeletedWebhook": ".types",
+ "PageDeletedWebhookPayload": ".types",
+ "PageDomWriteNodesItem": ".resources",
+ "PageList": ".types",
+ "PageMetadataUpdatedWebhook": ".types",
+ "PageMetadataUpdatedWebhookPayload": ".types",
+ "PageMetadataWriteOpenGraph": ".resources",
+ "PageMetadataWriteSeo": ".resources",
+ "PageOpenGraph": ".types",
+ "PageSeo": ".types",
+ "Pagination": ".types",
+ "Payload": ".types",
+ "PayloadFieldData": ".types",
+ "PaypalDetails": ".types",
+ "Product": ".types",
+ "ProductAndSkUs": ".types",
+ "ProductAndSkUsList": ".types",
+ "ProductFieldData": ".types",
+ "ProductFieldDataEcProductType": ".types",
+ "ProductFieldDataTaxCategory": ".types",
+ "ProductSkuCreateProduct": ".resources",
+ "ProductSkuCreateSku": ".resources",
+ "ProductsCreateSkuResponse": ".resources",
+ "PublishStatus": ".types",
+ "Redirect": ".types",
+ "Redirects": ".types",
+ "ReferenceField": ".types",
+ "ReferenceFieldMetadata": ".types",
+ "ReferenceFieldType": ".types",
+ "RegisteredScriptList": ".types",
+ "Robots": ".types",
+ "RobotsRulesItem": ".types",
+ "ScriptApply": ".types",
+ "ScriptApplyList": ".types",
+ "ScriptApplyLocation": ".types",
+ "Scripts": ".types",
+ "SearchButtonNode": ".types",
+ "SearchButtonNodeWrite": ".types",
+ "Select": ".types",
+ "SelectNode": ".types",
+ "SelectNodeChoicesItem": ".types",
+ "SelectNodeWriteChoicesItem": ".types",
+ "SettingChange": ".types",
+ "SettingChangeAuditLogItem": ".types",
+ "SingleLocaleCreatedPayload": ".types",
+ "SingleLocaleCreatedPayloadFieldData": ".types",
+ "Site": ".types",
+ "SiteActivityLogItem": ".types",
+ "SiteActivityLogItemEvent": ".types",
+ "SiteActivityLogItemResourceOperation": ".types",
+ "SiteActivityLogItemUser": ".types",
+ "SiteActivityLogResponse": ".types",
+ "SiteDataCollectionType": ".types",
+ "SiteMembership": ".types",
+ "SiteMembershipAuditLogItem": ".types",
+ "SiteMembershipAuditLogItemEventSubType": ".types",
+ "SitePlan": ".types",
+ "SitePlanId": ".types",
+ "SitePlanName": ".types",
+ "SitePublish": ".types",
+ "SitePublishPayload": ".types",
+ "Sites": ".types",
+ "SitesPublishResponse": ".resources",
+ "Sku": ".types",
+ "SkuFieldData": ".types",
+ "SkuFieldDataCompareAtPrice": ".types",
+ "SkuFieldDataEcSkuBillingMethod": ".types",
+ "SkuFieldDataEcSkuSubscriptionPlan": ".types",
+ "SkuFieldDataEcSkuSubscriptionPlanInterval": ".types",
+ "SkuFieldDataEcSkuSubscriptionPlanPlansItem": ".types",
+ "SkuFieldDataEcSkuSubscriptionPlanPlansItemStatus": ".types",
+ "SkuFieldDataPrice": ".types",
+ "SkuPropertyList": ".types",
+ "SkuPropertyListEnumItem": ".types",
+ "SkuValueList": ".types",
+ "StaticField": ".types",
+ "StaticFieldType": ".types",
+ "StripeCard": ".types",
+ "StripeCardBrand": ".types",
+ "StripeCardExpires": ".types",
+ "StripeDetails": ".types",
+ "SubmitButtonNode": ".types",
+ "SubmitButtonNodeWrite": ".types",
+ "Text": ".types",
+ "TextInputNode": ".types",
+ "TextInputNodeWrite": ".types",
+ "TextNode": ".types",
+ "TextNodeText": ".types",
+ "TextNodeWrite": ".types",
+ "TooManyRequestsError": ".errors",
+ "TriggerType": ".types",
+ "UnauthorizedError": ".errors",
+ "UpdateStaticContentResponse": ".resources",
+ "UpdatedOrder": ".types",
+ "UserAccess": ".types",
+ "UserAccessAuditLogItem": ".types",
+ "UserAccessAuditLogItemEventSubType": ".types",
+ "Webflow": ".client",
+ "WebflowEnvironment": ".environment",
+ "Webhook": ".types",
+ "WebhookFilter": ".types",
+ "WebhookList": ".types",
+ "WorkspaceAuditLogItem": ".types",
+ "WorkspaceAuditLogItemActor": ".types",
+ "WorkspaceAuditLogItemPayloadSettingChangeMethod": ".types",
+ "WorkspaceAuditLogItemPayloadSiteMembershipGranularAccess": ".types",
+ "WorkspaceAuditLogItemPayloadSiteMembershipMethod": ".types",
+ "WorkspaceAuditLogItemPayloadSiteMembershipSite": ".types",
+ "WorkspaceAuditLogItemPayloadSiteMembershipTargetUser": ".types",
+ "WorkspaceAuditLogItemPayloadSiteMembershipUserType": ".types",
+ "WorkspaceAuditLogItemPayloadUserAccessMethod": ".types",
+ "WorkspaceAuditLogItemPayloadWorkspaceInvitationMethod": ".types",
+ "WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUser": ".types",
+ "WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUsersItem": ".types",
+ "WorkspaceAuditLogItemPayloadWorkspaceInvitationUserType": ".types",
+ "WorkspaceAuditLogItemPayloadWorkspaceMembershipMethod": ".types",
+ "WorkspaceAuditLogItemPayloadWorkspaceMembershipTargetUser": ".types",
+ "WorkspaceAuditLogItemPayloadWorkspaceMembershipUserType": ".types",
+ "WorkspaceAuditLogItemWorkspace": ".types",
+ "WorkspaceAuditLogItem_CustomRole": ".types",
+ "WorkspaceAuditLogItem_SiteMembership": ".types",
+ "WorkspaceAuditLogItem_UserAccess": ".types",
+ "WorkspaceAuditLogItem_WorkspaceInvitation": ".types",
+ "WorkspaceAuditLogItem_WorkspaceMembership": ".types",
+ "WorkspaceAuditLogItem_WorkspaceSetting": ".types",
+ "WorkspaceAuditLogResponse": ".types",
+ "WorkspaceInvitation": ".types",
+ "WorkspaceInvitationAuditLogItem": ".types",
+ "WorkspaceInvitationAuditLogItemEventSubType": ".types",
+ "WorkspaceMembership": ".types",
+ "WorkspaceMembershipAuditLogItem": ".types",
+ "WorkspaceMembershipAuditLogItemEventSubType": ".types",
+ "__version__": ".version",
+ "assets": ".resources",
+ "collections": ".resources",
+ "components": ".resources",
+ "ecommerce": ".resources",
+ "forms": ".resources",
+ "inventory": ".resources",
+ "orders": ".resources",
+ "pages": ".resources",
+ "products": ".resources",
+ "scripts": ".resources",
+ "sites": ".resources",
+ "token": ".resources",
+ "webhooks": ".resources",
+ "workspaces": ".resources",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
__all__ = [
- "AccessGroup",
- "AccessGroupList",
- "AccessGroupsListRequestSort",
"Application",
"Asset",
"AssetFolder",
@@ -179,33 +661,89 @@
"AssetUploadUploadDetails",
"AssetVariant",
"Assets",
+ "AsyncWebflow",
"Authorization",
"AuthorizationAuthorization",
"AuthorizationAuthorizationAuthorizedTo",
"AuthorizedUser",
"BadRequestError",
+ "BadRequestErrorBody",
+ "BulkCollectionItem",
+ "BulkCollectionItemFieldData",
"Collection",
"CollectionItem",
+ "CollectionItemChanged",
+ "CollectionItemCreated",
"CollectionItemFieldData",
"CollectionItemList",
+ "CollectionItemListNoPagination",
"CollectionItemListPagination",
+ "CollectionItemPatchSingle",
+ "CollectionItemPatchSingleFieldData",
+ "CollectionItemPostSingle",
+ "CollectionItemPostSingleFieldData",
+ "CollectionItemPublished",
+ "CollectionItemRemoved",
+ "CollectionItemRemovedPayload",
+ "CollectionItemRemovedPayloadFieldData",
+ "CollectionItemUnpublished",
+ "CollectionItemUnpublishedPayload",
+ "CollectionItemUnpublishedPayloadFieldData",
+ "CollectionItemWithIdInput",
+ "CollectionItemWithIdInputFieldData",
"CollectionList",
"CollectionListArrayItem",
+ "Comment",
+ "CommentPayload",
+ "CommentPayloadAuthor",
+ "CommentPayloadMentionedUsersItem",
+ "CommentReply",
+ "CommentReplyAuthor",
+ "CommentReplyList",
+ "CommentReplyListPagination",
+ "CommentReplyMentionedUsersItem",
+ "CommentThread",
+ "CommentThreadAuthor",
+ "CommentThreadList",
+ "CommentThreadListPagination",
+ "CommentThreadMentionedUsersItem",
+ "Component",
+ "ComponentDom",
+ "ComponentDomWriteNodesItem",
+ "ComponentInstanceNodePropertyOverridesWrite",
+ "ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem",
+ "ComponentList",
+ "ComponentNode",
+ "ComponentProperties",
+ "ComponentPropertiesWritePropertiesItem",
+ "ComponentProperty",
+ "ComponentPropertyType",
+ "ComponentsUpdateContentResponse",
+ "ComponentsUpdatePropertiesResponse",
+ "Conflict",
"ConflictError",
"CustomCodeBlock",
"CustomCodeBlockType",
- "CustomCodeResponse",
+ "CustomCodeHostedResponse",
+ "CustomCodeInlineResponse",
+ "CustomRole",
+ "CustomRoleAuditLogItem",
+ "CustomRoleAuditLogItemEventSubType",
"Dom",
- "DomWriteNodesItem",
"Domain",
"Domains",
- "DuplicateUserEmail",
+ "EcommInventoryChangedPayload",
"EcommerceSettings",
"Error",
- "ErrorDetailsItem",
+ "ErrorCode",
"Field",
+ "FieldCreate",
"FieldType",
+ "FieldValidations",
+ "FieldValidationsAdditionalProperties",
+ "FieldValidationsAdditionalPropertiesAdditionalProperties",
"ForbiddenError",
+ "ForbiddenErrorBody",
"Form",
"FormField",
"FormFieldValue",
@@ -214,24 +752,46 @@
"FormResponseSettings",
"FormSubmission",
"FormSubmissionList",
+ "FormSubmissionTrigger",
+ "FormSubmissionTriggerPayload",
+ "FormSubmissionTriggerPayloadSchemaItem",
+ "FormSubmissionTriggerPayloadSchemaItemFieldType",
"ImageNode",
+ "ImageNodeImage",
"InternalServerError",
"InvalidDomain",
+ "InvalidScopes",
"InventoryItem",
"InventoryItemInventoryType",
"InventoryUpdateRequestInventoryType",
+ "ItemsListItemsLiveRequestLastPublished",
+ "ItemsListItemsRequestLastPublished",
"ListCustomCodeBlocks",
- "MissingScopes",
+ "Locale",
+ "Locales",
+ "Metadata",
+ "MetadataOptionsItem",
+ "NewOrder",
"NoDomains",
"Node",
- "NodeType",
+ "Node_ComponentInstance",
+ "Node_Image",
+ "Node_SearchButton",
+ "Node_Select",
+ "Node_SubmitButton",
+ "Node_Text",
+ "Node_TextInput",
"NotEnterprisePlanSite",
+ "NotEnterprisePlanWorkspace",
"NotFoundError",
- "OauthScope",
+ "OptionField",
"Order",
"OrderAddress",
"OrderAddressJapanType",
"OrderAddressType",
+ "OrderBillingAddress",
+ "OrderBillingAddressJapanType",
+ "OrderBillingAddressType",
"OrderCustomerInfo",
"OrderDisputeLastStatus",
"OrderDownloadFilesItem",
@@ -242,16 +802,31 @@
"OrderPurchasedItemVariantImage",
"OrderPurchasedItemVariantImageFile",
"OrderPurchasedItemVariantImageFileVariantsItem",
+ "OrderShippingAddress",
+ "OrderShippingAddressJapanType",
+ "OrderShippingAddressType",
"OrderStatus",
"OrderTotals",
"OrderTotalsExtrasItem",
"OrderTotalsExtrasItemType",
+ "OrdersListRequestStatus",
"OrdersRefundRequestReason",
"Page",
+ "PageCreatedWebhook",
+ "PageCreatedWebhookPayload",
+ "PageDeletedWebhook",
+ "PageDeletedWebhookPayload",
+ "PageDomWriteNodesItem",
"PageList",
+ "PageMetadataUpdatedWebhook",
+ "PageMetadataUpdatedWebhookPayload",
+ "PageMetadataWriteOpenGraph",
+ "PageMetadataWriteSeo",
"PageOpenGraph",
"PageSeo",
"Pagination",
+ "Payload",
+ "PayloadFieldData",
"PaypalDetails",
"Product",
"ProductAndSkUs",
@@ -260,63 +835,121 @@
"ProductFieldDataEcProductType",
"ProductFieldDataTaxCategory",
"ProductSkuCreateProduct",
- "ProductSkuCreateProductFieldData",
- "ProductSkuCreateProductFieldDataEcProductType",
- "ProductSkuCreateProductFieldDataTaxCategory",
"ProductSkuCreateSku",
- "ProductSkuCreateSkuFieldData",
- "ProductSkuCreateSkuFieldDataCompareAtPrice",
- "ProductSkuCreateSkuFieldDataEcSkuBillingMethod",
- "ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlan",
- "ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlanInterval",
- "ProductSkuCreateSkuFieldDataPrice",
"ProductsCreateSkuResponse",
"PublishStatus",
+ "Redirect",
+ "Redirects",
+ "ReferenceField",
+ "ReferenceFieldMetadata",
+ "ReferenceFieldType",
"RegisteredScriptList",
+ "Robots",
+ "RobotsRulesItem",
"ScriptApply",
"ScriptApplyList",
"ScriptApplyLocation",
"Scripts",
+ "SearchButtonNode",
+ "SearchButtonNodeWrite",
+ "Select",
+ "SelectNode",
+ "SelectNodeChoicesItem",
+ "SelectNodeWriteChoicesItem",
+ "SettingChange",
+ "SettingChangeAuditLogItem",
+ "SingleLocaleCreatedPayload",
+ "SingleLocaleCreatedPayloadFieldData",
"Site",
"SiteActivityLogItem",
+ "SiteActivityLogItemEvent",
"SiteActivityLogItemResourceOperation",
"SiteActivityLogItemUser",
"SiteActivityLogResponse",
+ "SiteDataCollectionType",
+ "SiteMembership",
+ "SiteMembershipAuditLogItem",
+ "SiteMembershipAuditLogItemEventSubType",
+ "SitePlan",
+ "SitePlanId",
+ "SitePlanName",
+ "SitePublish",
+ "SitePublishPayload",
+ "Sites",
+ "SitesPublishResponse",
"Sku",
"SkuFieldData",
"SkuFieldDataCompareAtPrice",
"SkuFieldDataEcSkuBillingMethod",
"SkuFieldDataEcSkuSubscriptionPlan",
"SkuFieldDataEcSkuSubscriptionPlanInterval",
+ "SkuFieldDataEcSkuSubscriptionPlanPlansItem",
+ "SkuFieldDataEcSkuSubscriptionPlanPlansItemStatus",
"SkuFieldDataPrice",
"SkuPropertyList",
"SkuPropertyListEnumItem",
"SkuValueList",
+ "StaticField",
+ "StaticFieldType",
"StripeCard",
"StripeCardBrand",
"StripeCardExpires",
"StripeDetails",
+ "SubmitButtonNode",
+ "SubmitButtonNodeWrite",
+ "Text",
+ "TextInputNode",
+ "TextInputNodeWrite",
"TextNode",
+ "TextNodeText",
+ "TextNodeWrite",
"TooManyRequestsError",
"TriggerType",
"UnauthorizedError",
- "User",
- "UserAccessGroupsItem",
- "UserAccessGroupsItemType",
- "UserData",
- "UserDataData",
- "UserLimitReached",
- "UserList",
- "UserStatus",
- "UsersListRequestSort",
- "UsersNotEnabled",
- "UsersUpdateRequestData",
+ "UpdateStaticContentResponse",
+ "UpdatedOrder",
+ "UserAccess",
+ "UserAccessAuditLogItem",
+ "UserAccessAuditLogItemEventSubType",
+ "Webflow",
"WebflowEnvironment",
"Webhook",
+ "WebhookFilter",
"WebhookList",
- "access_groups",
+ "WorkspaceAuditLogItem",
+ "WorkspaceAuditLogItemActor",
+ "WorkspaceAuditLogItemPayloadSettingChangeMethod",
+ "WorkspaceAuditLogItemPayloadSiteMembershipGranularAccess",
+ "WorkspaceAuditLogItemPayloadSiteMembershipMethod",
+ "WorkspaceAuditLogItemPayloadSiteMembershipSite",
+ "WorkspaceAuditLogItemPayloadSiteMembershipTargetUser",
+ "WorkspaceAuditLogItemPayloadSiteMembershipUserType",
+ "WorkspaceAuditLogItemPayloadUserAccessMethod",
+ "WorkspaceAuditLogItemPayloadWorkspaceInvitationMethod",
+ "WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUser",
+ "WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUsersItem",
+ "WorkspaceAuditLogItemPayloadWorkspaceInvitationUserType",
+ "WorkspaceAuditLogItemPayloadWorkspaceMembershipMethod",
+ "WorkspaceAuditLogItemPayloadWorkspaceMembershipTargetUser",
+ "WorkspaceAuditLogItemPayloadWorkspaceMembershipUserType",
+ "WorkspaceAuditLogItemWorkspace",
+ "WorkspaceAuditLogItem_CustomRole",
+ "WorkspaceAuditLogItem_SiteMembership",
+ "WorkspaceAuditLogItem_UserAccess",
+ "WorkspaceAuditLogItem_WorkspaceInvitation",
+ "WorkspaceAuditLogItem_WorkspaceMembership",
+ "WorkspaceAuditLogItem_WorkspaceSetting",
+ "WorkspaceAuditLogResponse",
+ "WorkspaceInvitation",
+ "WorkspaceInvitationAuditLogItem",
+ "WorkspaceInvitationAuditLogItemEventSubType",
+ "WorkspaceMembership",
+ "WorkspaceMembershipAuditLogItem",
+ "WorkspaceMembershipAuditLogItemEventSubType",
+ "__version__",
"assets",
"collections",
+ "components",
"ecommerce",
"forms",
"inventory",
@@ -326,6 +959,6 @@
"scripts",
"sites",
"token",
- "users",
"webhooks",
+ "workspaces",
]
diff --git a/src/webflow/client.py b/src/webflow/client.py
index 493b3bd..bc75156 100644
--- a/src/webflow/client.py
+++ b/src/webflow/client.py
@@ -1,45 +1,65 @@
# This file was auto-generated by Fern from our API Definition.
+from __future__ import annotations
+
import typing
import httpx
-
from .core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .core.logging import LogConfig, Logger
from .environment import WebflowEnvironment
-from .resources.access_groups.client import AccessGroupsClient, AsyncAccessGroupsClient
-from .resources.assets.client import AssetsClient, AsyncAssetsClient
-from .resources.collections.client import AsyncCollectionsClient, CollectionsClient
-from .resources.ecommerce.client import AsyncEcommerceClient, EcommerceClient
-from .resources.forms.client import AsyncFormsClient, FormsClient
-from .resources.inventory.client import AsyncInventoryClient, InventoryClient
-from .resources.orders.client import AsyncOrdersClient, OrdersClient
-from .resources.pages.client import AsyncPagesClient, PagesClient
-from .resources.products.client import AsyncProductsClient, ProductsClient
-from .resources.scripts.client import AsyncScriptsClient, ScriptsClient
-from .resources.sites.client import AsyncSitesClient, SitesClient
-from .resources.token.client import AsyncTokenClient, TokenClient
-from .resources.users.client import AsyncUsersClient, UsersClient
-from .resources.webhooks.client import AsyncWebhooksClient, WebhooksClient
+
+if typing.TYPE_CHECKING:
+ from .resources.assets.client import AssetsClient, AsyncAssetsClient
+ from .resources.collections.client import AsyncCollectionsClient, CollectionsClient
+ from .resources.components.client import AsyncComponentsClient, ComponentsClient
+ from .resources.ecommerce.client import AsyncEcommerceClient, EcommerceClient
+ from .resources.forms.client import AsyncFormsClient, FormsClient
+ from .resources.inventory.client import AsyncInventoryClient, InventoryClient
+ from .resources.orders.client import AsyncOrdersClient, OrdersClient
+ from .resources.pages.client import AsyncPagesClient, PagesClient
+ from .resources.products.client import AsyncProductsClient, ProductsClient
+ from .resources.scripts.client import AsyncScriptsClient, ScriptsClient
+ from .resources.sites.client import AsyncSitesClient, SitesClient
+ from .resources.token.client import AsyncTokenClient, TokenClient
+ from .resources.webhooks.client import AsyncWebhooksClient, WebhooksClient
+ from .resources.workspaces.client import AsyncWorkspacesClient, WorkspacesClient
class Webflow:
"""
- Use this class to access the different functions within the SDK. You can instantiate any number of clients with different configuration that will propogate to these functions.
+ Use this class to access the different functions within the SDK. You can instantiate any number of clients with different configuration that will propagate to these functions.
+
+ Parameters
+ ----------
+ environment : WebflowEnvironment
+ The environment to use for requests from the client. from .environment import WebflowEnvironment
+
- 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.DATA_API
- Defaults to WebflowEnvironment.DEFAULT
- - access_token: typing.Union[str, typing.Callable[[], str]].
- - timeout: typing.Optional[float]. The timeout to be used, in seconds, for requests by default the timeout is 60 seconds.
+ access_token : typing.Union[str, typing.Callable[[], str]]
+ headers : typing.Optional[typing.Dict[str, str]]
+ Additional headers to send with every request.
- - httpx_client: typing.Optional[httpx.Client]. The httpx client to use for making requests, a preconfigured client is used by default, however this is useful should you want to pass in any custom httpx configuration.
- ---
- from webflow.client import Webflow
+ timeout : typing.Optional[float]
+ The timeout to be used, in seconds, for requests. By default the timeout is 60 seconds, unless a custom httpx client is used, in which case this default is not enforced.
+
+ follow_redirects : typing.Optional[bool]
+ Whether the default httpx client follows redirects or not, this is irrelevant if a custom httpx client is passed in.
+
+ httpx_client : typing.Optional[httpx.Client]
+ The httpx client to use for making requests, a preconfigured client is used by default, however this is useful should you want to pass in any custom httpx configuration.
+
+ logging : typing.Optional[typing.Union[LogConfig, Logger]]
+ Configure logging for the SDK. Accepts a LogConfig dict with 'level' (debug/info/warn/error), 'logger' (custom logger implementation), and 'silent' (boolean, defaults to True) fields. You can also pass a pre-configured Logger instance.
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
@@ -49,51 +69,191 @@ 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] = 60,
- httpx_client: typing.Optional[httpx.Client] = None
+ headers: typing.Optional[typing.Dict[str, str]] = None,
+ timeout: typing.Optional[float] = None,
+ follow_redirects: typing.Optional[bool] = True,
+ httpx_client: typing.Optional[httpx.Client] = None,
+ logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
):
+ _defaulted_timeout = (
+ timeout if timeout is not None else 60 if httpx_client is None else httpx_client.timeout.read
+ )
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(timeout=timeout) if httpx_client is None else httpx_client,
+ headers=headers,
+ httpx_client=httpx_client
+ if httpx_client is not None
+ else httpx.Client(timeout=_defaulted_timeout, follow_redirects=follow_redirects)
+ if follow_redirects is not None
+ else httpx.Client(timeout=_defaulted_timeout),
+ timeout=_defaulted_timeout,
+ logging=logging,
)
- self.token = TokenClient(client_wrapper=self._client_wrapper)
- self.sites = SitesClient(client_wrapper=self._client_wrapper)
- self.collections = CollectionsClient(client_wrapper=self._client_wrapper)
- self.pages = PagesClient(client_wrapper=self._client_wrapper)
- self.scripts = ScriptsClient(client_wrapper=self._client_wrapper)
- self.assets = AssetsClient(client_wrapper=self._client_wrapper)
- self.webhooks = WebhooksClient(client_wrapper=self._client_wrapper)
- self.forms = FormsClient(client_wrapper=self._client_wrapper)
- self.users = UsersClient(client_wrapper=self._client_wrapper)
- self.access_groups = AccessGroupsClient(client_wrapper=self._client_wrapper)
- self.products = ProductsClient(client_wrapper=self._client_wrapper)
- 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._token: typing.Optional[TokenClient] = None
+ self._sites: typing.Optional[SitesClient] = None
+ self._collections: typing.Optional[CollectionsClient] = None
+ self._pages: typing.Optional[PagesClient] = None
+ self._components: typing.Optional[ComponentsClient] = None
+ self._scripts: typing.Optional[ScriptsClient] = None
+ self._assets: typing.Optional[AssetsClient] = None
+ self._webhooks: typing.Optional[WebhooksClient] = None
+ self._forms: typing.Optional[FormsClient] = None
+ self._products: typing.Optional[ProductsClient] = None
+ self._orders: typing.Optional[OrdersClient] = None
+ self._inventory: typing.Optional[InventoryClient] = None
+ self._ecommerce: typing.Optional[EcommerceClient] = None
+ self._workspaces: typing.Optional[WorkspacesClient] = None
+
+ @property
+ def token(self):
+ if self._token is None:
+ from .resources.token.client import TokenClient # noqa: E402
+
+ self._token = TokenClient(client_wrapper=self._client_wrapper)
+ return self._token
+
+ @property
+ def sites(self):
+ if self._sites is None:
+ from .resources.sites.client import SitesClient # noqa: E402
+
+ self._sites = SitesClient(client_wrapper=self._client_wrapper)
+ return self._sites
+
+ @property
+ def collections(self):
+ if self._collections is None:
+ from .resources.collections.client import CollectionsClient # noqa: E402
+
+ self._collections = CollectionsClient(client_wrapper=self._client_wrapper)
+ return self._collections
+
+ @property
+ def pages(self):
+ if self._pages is None:
+ from .resources.pages.client import PagesClient # noqa: E402
+
+ self._pages = PagesClient(client_wrapper=self._client_wrapper)
+ return self._pages
+
+ @property
+ def components(self):
+ if self._components is None:
+ from .resources.components.client import ComponentsClient # noqa: E402
+
+ self._components = ComponentsClient(client_wrapper=self._client_wrapper)
+ return self._components
+
+ @property
+ def scripts(self):
+ if self._scripts is None:
+ from .resources.scripts.client import ScriptsClient # noqa: E402
+
+ self._scripts = ScriptsClient(client_wrapper=self._client_wrapper)
+ return self._scripts
+
+ @property
+ def assets(self):
+ if self._assets is None:
+ from .resources.assets.client import AssetsClient # noqa: E402
+
+ self._assets = AssetsClient(client_wrapper=self._client_wrapper)
+ return self._assets
+
+ @property
+ def webhooks(self):
+ if self._webhooks is None:
+ from .resources.webhooks.client import WebhooksClient # noqa: E402
+
+ self._webhooks = WebhooksClient(client_wrapper=self._client_wrapper)
+ return self._webhooks
+
+ @property
+ def forms(self):
+ if self._forms is None:
+ from .resources.forms.client import FormsClient # noqa: E402
+
+ self._forms = FormsClient(client_wrapper=self._client_wrapper)
+ return self._forms
+
+ @property
+ def products(self):
+ if self._products is None:
+ from .resources.products.client import ProductsClient # noqa: E402
+
+ self._products = ProductsClient(client_wrapper=self._client_wrapper)
+ return self._products
+
+ @property
+ def orders(self):
+ if self._orders is None:
+ from .resources.orders.client import OrdersClient # noqa: E402
+
+ self._orders = OrdersClient(client_wrapper=self._client_wrapper)
+ return self._orders
+
+ @property
+ def inventory(self):
+ if self._inventory is None:
+ from .resources.inventory.client import InventoryClient # noqa: E402
+
+ self._inventory = InventoryClient(client_wrapper=self._client_wrapper)
+ return self._inventory
+
+ @property
+ def ecommerce(self):
+ if self._ecommerce is None:
+ from .resources.ecommerce.client import EcommerceClient # noqa: E402
+
+ self._ecommerce = EcommerceClient(client_wrapper=self._client_wrapper)
+ return self._ecommerce
+
+ @property
+ def workspaces(self):
+ if self._workspaces is None:
+ from .resources.workspaces.client import WorkspacesClient # noqa: E402
+
+ self._workspaces = WorkspacesClient(client_wrapper=self._client_wrapper)
+ return self._workspaces
class AsyncWebflow:
"""
- Use this class to access the different functions within the SDK. You can instantiate any number of clients with different configuration that will propogate to these functions.
+ Use this class to access the different functions within the SDK. You can instantiate any number of clients with different configuration that will propagate to these functions.
+
+ Parameters
+ ----------
+ environment : WebflowEnvironment
+ The environment to use for requests from the client. from .environment import WebflowEnvironment
+
+
+
+ Defaults to WebflowEnvironment.DATA_API
- 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
+ access_token : typing.Union[str, typing.Callable[[], str]]
+ headers : typing.Optional[typing.Dict[str, str]]
+ Additional headers to send with every request.
- - access_token: typing.Union[str, typing.Callable[[], str]].
+ timeout : typing.Optional[float]
+ The timeout to be used, in seconds, for requests. By default the timeout is 60 seconds, unless a custom httpx client is used, in which case this default is not enforced.
- - timeout: typing.Optional[float]. The timeout to be used, in seconds, for requests by default the timeout is 60 seconds.
+ follow_redirects : typing.Optional[bool]
+ Whether the default httpx client follows redirects or not, this is irrelevant if a custom httpx client is passed in.
- - httpx_client: typing.Optional[httpx.AsyncClient]. The httpx client to use for making requests, a preconfigured client is used by default, however this is useful should you want to pass in any custom httpx configuration.
- ---
- from webflow.client import AsyncWebflow
+ httpx_client : typing.Optional[httpx.AsyncClient]
+ The httpx client to use for making requests, a preconfigured client is used by default, however this is useful should you want to pass in any custom httpx configuration.
+
+ logging : typing.Optional[typing.Union[LogConfig, Logger]]
+ Configure logging for the SDK. Accepts a LogConfig dict with 'level' (debug/info/warn/error), 'logger' (custom logger implementation), and 'silent' (boolean, defaults to True) fields. You can also pass a pre-configured Logger instance.
+
+ Examples
+ --------
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
@@ -103,37 +263,152 @@ 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] = 60,
- httpx_client: typing.Optional[httpx.AsyncClient] = None
+ headers: typing.Optional[typing.Dict[str, str]] = None,
+ timeout: typing.Optional[float] = None,
+ follow_redirects: typing.Optional[bool] = True,
+ httpx_client: typing.Optional[httpx.AsyncClient] = None,
+ logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
):
+ _defaulted_timeout = (
+ timeout if timeout is not None else 60 if httpx_client is None else httpx_client.timeout.read
+ )
self._client_wrapper = AsyncClientWrapper(
- base_url=_get_base_url(base_url=base_url, environment=environment),
+ environment=environment,
access_token=access_token,
- httpx_client=httpx.AsyncClient(timeout=timeout) if httpx_client is None else httpx_client,
+ headers=headers,
+ httpx_client=httpx_client
+ if httpx_client is not None
+ else httpx.AsyncClient(timeout=_defaulted_timeout, follow_redirects=follow_redirects)
+ if follow_redirects is not None
+ else httpx.AsyncClient(timeout=_defaulted_timeout),
+ timeout=_defaulted_timeout,
+ logging=logging,
)
- self.token = AsyncTokenClient(client_wrapper=self._client_wrapper)
- self.sites = AsyncSitesClient(client_wrapper=self._client_wrapper)
- self.collections = AsyncCollectionsClient(client_wrapper=self._client_wrapper)
- self.pages = AsyncPagesClient(client_wrapper=self._client_wrapper)
- self.scripts = AsyncScriptsClient(client_wrapper=self._client_wrapper)
- self.assets = AsyncAssetsClient(client_wrapper=self._client_wrapper)
- self.webhooks = AsyncWebhooksClient(client_wrapper=self._client_wrapper)
- self.forms = AsyncFormsClient(client_wrapper=self._client_wrapper)
- self.users = AsyncUsersClient(client_wrapper=self._client_wrapper)
- self.access_groups = AsyncAccessGroupsClient(client_wrapper=self._client_wrapper)
- self.products = AsyncProductsClient(client_wrapper=self._client_wrapper)
- 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._token: typing.Optional[AsyncTokenClient] = None
+ self._sites: typing.Optional[AsyncSitesClient] = None
+ self._collections: typing.Optional[AsyncCollectionsClient] = None
+ self._pages: typing.Optional[AsyncPagesClient] = None
+ self._components: typing.Optional[AsyncComponentsClient] = None
+ self._scripts: typing.Optional[AsyncScriptsClient] = None
+ self._assets: typing.Optional[AsyncAssetsClient] = None
+ self._webhooks: typing.Optional[AsyncWebhooksClient] = None
+ self._forms: typing.Optional[AsyncFormsClient] = None
+ self._products: typing.Optional[AsyncProductsClient] = None
+ self._orders: typing.Optional[AsyncOrdersClient] = None
+ self._inventory: typing.Optional[AsyncInventoryClient] = None
+ self._ecommerce: typing.Optional[AsyncEcommerceClient] = None
+ self._workspaces: typing.Optional[AsyncWorkspacesClient] = None
+
+ @property
+ def token(self):
+ if self._token is None:
+ from .resources.token.client import AsyncTokenClient # noqa: E402
+
+ self._token = AsyncTokenClient(client_wrapper=self._client_wrapper)
+ return self._token
+
+ @property
+ def sites(self):
+ if self._sites is None:
+ from .resources.sites.client import AsyncSitesClient # noqa: E402
+
+ self._sites = AsyncSitesClient(client_wrapper=self._client_wrapper)
+ return self._sites
+
+ @property
+ def collections(self):
+ if self._collections is None:
+ from .resources.collections.client import AsyncCollectionsClient # noqa: E402
+
+ self._collections = AsyncCollectionsClient(client_wrapper=self._client_wrapper)
+ return self._collections
+
+ @property
+ def pages(self):
+ if self._pages is None:
+ from .resources.pages.client import AsyncPagesClient # noqa: E402
+
+ self._pages = AsyncPagesClient(client_wrapper=self._client_wrapper)
+ return self._pages
+
+ @property
+ def components(self):
+ if self._components is None:
+ from .resources.components.client import AsyncComponentsClient # noqa: E402
+
+ self._components = AsyncComponentsClient(client_wrapper=self._client_wrapper)
+ return self._components
+
+ @property
+ def scripts(self):
+ if self._scripts is None:
+ from .resources.scripts.client import AsyncScriptsClient # noqa: E402
+
+ self._scripts = AsyncScriptsClient(client_wrapper=self._client_wrapper)
+ return self._scripts
+
+ @property
+ def assets(self):
+ if self._assets is None:
+ from .resources.assets.client import AsyncAssetsClient # noqa: E402
+
+ self._assets = AsyncAssetsClient(client_wrapper=self._client_wrapper)
+ return self._assets
+
+ @property
+ def webhooks(self):
+ if self._webhooks is None:
+ from .resources.webhooks.client import AsyncWebhooksClient # noqa: E402
+
+ self._webhooks = AsyncWebhooksClient(client_wrapper=self._client_wrapper)
+ return self._webhooks
+
+ @property
+ def forms(self):
+ if self._forms is None:
+ from .resources.forms.client import AsyncFormsClient # noqa: E402
+
+ self._forms = AsyncFormsClient(client_wrapper=self._client_wrapper)
+ return self._forms
+
+ @property
+ def products(self):
+ if self._products is None:
+ from .resources.products.client import AsyncProductsClient # noqa: E402
+
+ self._products = AsyncProductsClient(client_wrapper=self._client_wrapper)
+ return self._products
+
+ @property
+ def orders(self):
+ if self._orders is None:
+ from .resources.orders.client import AsyncOrdersClient # noqa: E402
+
+ self._orders = AsyncOrdersClient(client_wrapper=self._client_wrapper)
+ return self._orders
+
+ @property
+ def inventory(self):
+ if self._inventory is None:
+ from .resources.inventory.client import AsyncInventoryClient # noqa: E402
+
+ self._inventory = AsyncInventoryClient(client_wrapper=self._client_wrapper)
+ return self._inventory
+
+ @property
+ def ecommerce(self):
+ if self._ecommerce is None:
+ from .resources.ecommerce.client import AsyncEcommerceClient # noqa: E402
+
+ self._ecommerce = AsyncEcommerceClient(client_wrapper=self._client_wrapper)
+ return self._ecommerce
+
+ @property
+ def workspaces(self):
+ if self._workspaces is None:
+ from .resources.workspaces.client import AsyncWorkspacesClient # noqa: E402
+
+ self._workspaces = AsyncWorkspacesClient(client_wrapper=self._client_wrapper)
+ return self._workspaces
diff --git a/src/webflow/core/__init__.py b/src/webflow/core/__init__.py
index 4c53b36..4fb6e12 100644
--- a/src/webflow/core/__init__.py
+++ b/src/webflow/core/__init__.py
@@ -1,22 +1,125 @@
# This file was auto-generated by Fern from our API Definition.
-from .api_error import ApiError
-from .client_wrapper import AsyncClientWrapper, BaseClientWrapper, SyncClientWrapper
-from .datetime_utils import serialize_datetime
-from .file import File, convert_file_dict_to_httpx_tuples
-from .jsonable_encoder import jsonable_encoder
-from .remove_none_from_dict import remove_none_from_dict
-from .request_options import RequestOptions
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .api_error import ApiError
+ from .client_wrapper import AsyncClientWrapper, BaseClientWrapper, SyncClientWrapper
+ from .datetime_utils import Rfc2822DateTime, parse_rfc2822_datetime, serialize_datetime
+ from .file import File, convert_file_dict_to_httpx_tuples, with_content_type
+ from .http_client import AsyncHttpClient, HttpClient
+ from .http_response import AsyncHttpResponse, HttpResponse
+ from .jsonable_encoder import jsonable_encoder
+ from .logging import ConsoleLogger, ILogger, LogConfig, LogLevel, Logger, create_logger
+ from .parse_error import ParsingError
+ from .pydantic_utilities import (
+ IS_PYDANTIC_V2,
+ UniversalBaseModel,
+ UniversalRootModel,
+ parse_obj_as,
+ universal_field_validator,
+ universal_root_validator,
+ update_forward_refs,
+ )
+ from .query_encoder import encode_query
+ from .remove_none_from_dict import remove_none_from_dict
+ from .request_options import RequestOptions
+ from .serialization import FieldMetadata, convert_and_respect_annotation_metadata
+_dynamic_imports: typing.Dict[str, str] = {
+ "ApiError": ".api_error",
+ "AsyncClientWrapper": ".client_wrapper",
+ "AsyncHttpClient": ".http_client",
+ "AsyncHttpResponse": ".http_response",
+ "BaseClientWrapper": ".client_wrapper",
+ "ConsoleLogger": ".logging",
+ "FieldMetadata": ".serialization",
+ "File": ".file",
+ "HttpClient": ".http_client",
+ "HttpResponse": ".http_response",
+ "ILogger": ".logging",
+ "IS_PYDANTIC_V2": ".pydantic_utilities",
+ "LogConfig": ".logging",
+ "LogLevel": ".logging",
+ "Logger": ".logging",
+ "ParsingError": ".parse_error",
+ "RequestOptions": ".request_options",
+ "Rfc2822DateTime": ".datetime_utils",
+ "SyncClientWrapper": ".client_wrapper",
+ "UniversalBaseModel": ".pydantic_utilities",
+ "UniversalRootModel": ".pydantic_utilities",
+ "convert_and_respect_annotation_metadata": ".serialization",
+ "convert_file_dict_to_httpx_tuples": ".file",
+ "create_logger": ".logging",
+ "encode_query": ".query_encoder",
+ "jsonable_encoder": ".jsonable_encoder",
+ "parse_obj_as": ".pydantic_utilities",
+ "parse_rfc2822_datetime": ".datetime_utils",
+ "remove_none_from_dict": ".remove_none_from_dict",
+ "serialize_datetime": ".datetime_utils",
+ "universal_field_validator": ".pydantic_utilities",
+ "universal_root_validator": ".pydantic_utilities",
+ "update_forward_refs": ".pydantic_utilities",
+ "with_content_type": ".file",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
__all__ = [
"ApiError",
"AsyncClientWrapper",
+ "AsyncHttpClient",
+ "AsyncHttpResponse",
"BaseClientWrapper",
+ "ConsoleLogger",
+ "FieldMetadata",
"File",
+ "HttpClient",
+ "HttpResponse",
+ "ILogger",
+ "IS_PYDANTIC_V2",
+ "LogConfig",
+ "LogLevel",
+ "Logger",
+ "ParsingError",
"RequestOptions",
+ "Rfc2822DateTime",
"SyncClientWrapper",
+ "UniversalBaseModel",
+ "UniversalRootModel",
+ "convert_and_respect_annotation_metadata",
"convert_file_dict_to_httpx_tuples",
+ "create_logger",
+ "encode_query",
"jsonable_encoder",
+ "parse_obj_as",
+ "parse_rfc2822_datetime",
"remove_none_from_dict",
"serialize_datetime",
+ "universal_field_validator",
+ "universal_root_validator",
+ "update_forward_refs",
+ "with_content_type",
]
diff --git a/src/webflow/core/api_error.py b/src/webflow/core/api_error.py
index 2e9fc54..6f850a6 100644
--- a/src/webflow/core/api_error.py
+++ b/src/webflow/core/api_error.py
@@ -1,15 +1,23 @@
# This file was auto-generated by Fern from our API Definition.
-import typing
+from typing import Any, Dict, Optional
class ApiError(Exception):
- status_code: typing.Optional[int]
- body: typing.Any
+ headers: Optional[Dict[str, str]]
+ status_code: Optional[int]
+ body: Any
- def __init__(self, *, status_code: typing.Optional[int] = None, body: typing.Any = None):
+ def __init__(
+ self,
+ *,
+ headers: Optional[Dict[str, str]] = None,
+ status_code: Optional[int] = None,
+ body: Any = None,
+ ) -> None:
+ self.headers = headers
self.status_code = status_code
self.body = body
def __str__(self) -> str:
- return f"status_code: {self.status_code}, body: {self.body}"
+ return f"headers: {self.headers}, status_code: {self.status_code}, body: {self.body}"
diff --git a/src/webflow/core/client_wrapper.py b/src/webflow/core/client_wrapper.py
index 59bbfde..7f6db17 100644
--- a/src/webflow/core/client_wrapper.py
+++ b/src/webflow/core/client_wrapper.py
@@ -3,18 +3,38 @@
import typing
import httpx
+from ..environment import WebflowEnvironment
+from .http_client import AsyncHttpClient, HttpClient
+from .logging import LogConfig, Logger
class BaseClientWrapper:
- def __init__(self, *, access_token: typing.Union[str, typing.Callable[[], str]], base_url: str):
+ def __init__(
+ self,
+ *,
+ access_token: typing.Union[str, typing.Callable[[], str]],
+ headers: typing.Optional[typing.Dict[str, str]] = None,
+ environment: WebflowEnvironment,
+ timeout: typing.Optional[float] = None,
+ logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
+ ):
self._access_token = access_token
- self._base_url = base_url
+ self._headers = headers
+ self._environment = environment
+ self._timeout = timeout
+ self._logging = logging
def get_headers(self) -> typing.Dict[str, str]:
+ import platform
+
headers: typing.Dict[str, str] = {
+ "User-Agent": "webflow/2.0.0",
"X-Fern-Language": "Python",
+ "X-Fern-Runtime": f"python/{platform.python_version()}",
+ "X-Fern-Platform": f"{platform.system().lower()}/{platform.release()}",
"X-Fern-SDK-Name": "webflow",
- "X-Fern-SDK-Version": "v1.2.0",
+ "X-Fern-SDK-Version": "2.0.0",
+ **(self.get_custom_headers() or {}),
}
headers["Authorization"] = f"Bearer {self._get_access_token()}"
return headers
@@ -25,16 +45,36 @@ def _get_access_token(self) -> str:
else:
return self._access_token()
- def get_base_url(self) -> str:
- return self._base_url
+ def get_custom_headers(self) -> typing.Optional[typing.Dict[str, str]]:
+ return self._headers
+
+ def get_environment(self) -> WebflowEnvironment:
+ return self._environment
+
+ def get_timeout(self) -> typing.Optional[float]:
+ return self._timeout
class SyncClientWrapper(BaseClientWrapper):
def __init__(
- self, *, access_token: typing.Union[str, typing.Callable[[], str]], base_url: str, httpx_client: httpx.Client
+ self,
+ *,
+ access_token: typing.Union[str, typing.Callable[[], str]],
+ headers: typing.Optional[typing.Dict[str, str]] = None,
+ environment: WebflowEnvironment,
+ timeout: typing.Optional[float] = None,
+ logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
+ httpx_client: httpx.Client,
):
- super().__init__(access_token=access_token, base_url=base_url)
- self.httpx_client = httpx_client
+ super().__init__(
+ access_token=access_token, headers=headers, environment=environment, timeout=timeout, logging=logging
+ )
+ self.httpx_client = HttpClient(
+ httpx_client=httpx_client,
+ base_headers=self.get_headers,
+ base_timeout=self.get_timeout,
+ logging_config=self._logging,
+ )
class AsyncClientWrapper(BaseClientWrapper):
@@ -42,8 +82,28 @@ def __init__(
self,
*,
access_token: typing.Union[str, typing.Callable[[], str]],
- base_url: str,
+ headers: typing.Optional[typing.Dict[str, str]] = None,
+ environment: WebflowEnvironment,
+ timeout: typing.Optional[float] = None,
+ logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
+ async_token: typing.Optional[typing.Callable[[], typing.Awaitable[str]]] = None,
httpx_client: httpx.AsyncClient,
):
- super().__init__(access_token=access_token, base_url=base_url)
- self.httpx_client = httpx_client
+ super().__init__(
+ access_token=access_token, headers=headers, environment=environment, timeout=timeout, logging=logging
+ )
+ self._async_token = async_token
+ self.httpx_client = AsyncHttpClient(
+ httpx_client=httpx_client,
+ base_headers=self.get_headers,
+ base_timeout=self.get_timeout,
+ async_base_headers=self.async_get_headers,
+ logging_config=self._logging,
+ )
+
+ async def async_get_headers(self) -> typing.Dict[str, str]:
+ headers = self.get_headers()
+ if self._async_token is not None:
+ token = await self._async_token()
+ headers["Authorization"] = f"Bearer {token}"
+ return headers
diff --git a/src/webflow/core/datetime_utils.py b/src/webflow/core/datetime_utils.py
index 7c9864a..a12b2ad 100644
--- a/src/webflow/core/datetime_utils.py
+++ b/src/webflow/core/datetime_utils.py
@@ -1,6 +1,48 @@
# This file was auto-generated by Fern from our API Definition.
import datetime as dt
+from email.utils import parsedate_to_datetime
+from typing import Any
+
+import pydantic
+
+IS_PYDANTIC_V2 = pydantic.VERSION.startswith("2.")
+
+
+def parse_rfc2822_datetime(v: Any) -> dt.datetime:
+ """
+ Parse an RFC 2822 datetime string (e.g., "Wed, 02 Oct 2002 13:00:00 GMT")
+ into a datetime object. If the value is already a datetime, return it as-is.
+ Falls back to ISO 8601 parsing if RFC 2822 parsing fails.
+ """
+ if isinstance(v, dt.datetime):
+ return v
+ if isinstance(v, str):
+ try:
+ return parsedate_to_datetime(v)
+ except Exception:
+ pass
+ # Fallback to ISO 8601 parsing
+ return dt.datetime.fromisoformat(v.replace("Z", "+00:00"))
+ raise ValueError(f"Expected str or datetime, got {type(v)}")
+
+
+class Rfc2822DateTime(dt.datetime):
+ """A datetime subclass that parses RFC 2822 date strings.
+
+ On Pydantic V1, uses __get_validators__ for pre-validation.
+ On Pydantic V2, uses __get_pydantic_core_schema__ for BeforeValidator-style parsing.
+ """
+
+ @classmethod
+ def __get_validators__(cls): # type: ignore[no-untyped-def]
+ yield parse_rfc2822_datetime
+
+ @classmethod
+ def __get_pydantic_core_schema__(cls, _source_type: Any, _handler: Any) -> Any: # type: ignore[override]
+ from pydantic_core import core_schema
+
+ return core_schema.no_info_before_validator_function(parse_rfc2822_datetime, core_schema.datetime_schema())
def serialize_datetime(v: dt.datetime) -> str:
diff --git a/src/webflow/core/file.py b/src/webflow/core/file.py
index cb0d40b..44b0d27 100644
--- a/src/webflow/core/file.py
+++ b/src/webflow/core/file.py
@@ -1,25 +1,30 @@
# This file was auto-generated by Fern from our API Definition.
-import typing
+from typing import IO, Dict, List, Mapping, Optional, Tuple, Union, cast
# File typing inspired by the flexibility of types within the httpx library
# https://github.com/encode/httpx/blob/master/httpx/_types.py
-FileContent = typing.Union[typing.IO[bytes], bytes, str]
-File = typing.Union[
+FileContent = Union[IO[bytes], bytes, str]
+File = Union[
# file (or bytes)
FileContent,
# (filename, file (or bytes))
- typing.Tuple[typing.Optional[str], FileContent],
+ Tuple[Optional[str], FileContent],
# (filename, file (or bytes), content_type)
- typing.Tuple[typing.Optional[str], FileContent, typing.Optional[str]],
+ Tuple[Optional[str], FileContent, Optional[str]],
# (filename, file (or bytes), content_type, headers)
- typing.Tuple[typing.Optional[str], FileContent, typing.Optional[str], typing.Mapping[str, str]],
+ Tuple[
+ Optional[str],
+ FileContent,
+ Optional[str],
+ Mapping[str, str],
+ ],
]
def convert_file_dict_to_httpx_tuples(
- d: typing.Dict[str, typing.Union[File, typing.List[File]]]
-) -> typing.List[typing.Tuple[str, File]]:
+ d: Dict[str, Union[File, List[File]]],
+) -> List[Tuple[str, File]]:
"""
The format we use is a list of tuples, where the first element is the
name of the file and the second is the file object. Typically HTTPX wants
@@ -36,3 +41,27 @@ def convert_file_dict_to_httpx_tuples(
else:
httpx_tuples.append((key, file_like))
return httpx_tuples
+
+
+def with_content_type(*, file: File, default_content_type: str) -> File:
+ """
+ This function resolves to the file's content type, if provided, and defaults
+ to the default_content_type value if not.
+ """
+ if isinstance(file, tuple):
+ if len(file) == 2:
+ filename, content = cast(Tuple[Optional[str], FileContent], file) # type: ignore
+ return (filename, content, default_content_type)
+ elif len(file) == 3:
+ filename, content, file_content_type = cast(Tuple[Optional[str], FileContent, Optional[str]], file) # type: ignore
+ out_content_type = file_content_type or default_content_type
+ return (filename, content, out_content_type)
+ elif len(file) == 4:
+ filename, content, file_content_type, headers = cast( # type: ignore
+ Tuple[Optional[str], FileContent, Optional[str], Mapping[str, str]], file
+ )
+ out_content_type = file_content_type or default_content_type
+ return (filename, content, out_content_type, headers)
+ else:
+ raise ValueError(f"Unexpected tuple length: {len(file)}")
+ return (None, file, default_content_type)
diff --git a/src/webflow/core/force_multipart.py b/src/webflow/core/force_multipart.py
new file mode 100644
index 0000000..5440913
--- /dev/null
+++ b/src/webflow/core/force_multipart.py
@@ -0,0 +1,18 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from typing import Any, Dict
+
+
+class ForceMultipartDict(Dict[str, Any]):
+ """
+ A dictionary subclass that always evaluates to True in boolean contexts.
+
+ This is used to force multipart/form-data encoding in HTTP requests even when
+ the dictionary is empty, which would normally evaluate to False.
+ """
+
+ def __bool__(self) -> bool:
+ return True
+
+
+FORCE_MULTIPART = ForceMultipartDict()
diff --git a/src/webflow/core/http_client.py b/src/webflow/core/http_client.py
new file mode 100644
index 0000000..ee93758
--- /dev/null
+++ b/src/webflow/core/http_client.py
@@ -0,0 +1,776 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import asyncio
+import email.utils
+import re
+import time
+import typing
+from contextlib import asynccontextmanager, contextmanager
+from random import random
+
+import httpx
+from .file import File, convert_file_dict_to_httpx_tuples
+from .force_multipart import FORCE_MULTIPART
+from .jsonable_encoder import jsonable_encoder
+from .logging import LogConfig, Logger, create_logger
+from .query_encoder import encode_query
+from .remove_none_from_dict import remove_none_from_dict as remove_none_from_dict
+from .request_options import RequestOptions
+from httpx._types import RequestFiles
+
+INITIAL_RETRY_DELAY_SECONDS = 1.0
+MAX_RETRY_DELAY_SECONDS = 60.0
+JITTER_FACTOR = 0.2 # 20% random jitter
+
+
+def _parse_retry_after(response_headers: httpx.Headers) -> typing.Optional[float]:
+ """
+ This function parses the `Retry-After` header in a HTTP response and returns the number of seconds to wait.
+
+ Inspired by the urllib3 retry implementation.
+ """
+ retry_after_ms = response_headers.get("retry-after-ms")
+ if retry_after_ms is not None:
+ try:
+ return int(retry_after_ms) / 1000 if retry_after_ms > 0 else 0
+ except Exception:
+ pass
+
+ retry_after = response_headers.get("retry-after")
+ if retry_after is None:
+ return None
+
+ # Attempt to parse the header as an int.
+ if re.match(r"^\s*[0-9]+\s*$", retry_after):
+ seconds = float(retry_after)
+ # Fallback to parsing it as a date.
+ else:
+ retry_date_tuple = email.utils.parsedate_tz(retry_after)
+ if retry_date_tuple is None:
+ return None
+ if retry_date_tuple[9] is None: # Python 2
+ # Assume UTC if no timezone was specified
+ # On Python2.7, parsedate_tz returns None for a timezone offset
+ # instead of 0 if no timezone is given, where mktime_tz treats
+ # a None timezone offset as local time.
+ retry_date_tuple = retry_date_tuple[:9] + (0,) + retry_date_tuple[10:]
+
+ retry_date = email.utils.mktime_tz(retry_date_tuple)
+ seconds = retry_date - time.time()
+
+ if seconds < 0:
+ seconds = 0
+
+ return seconds
+
+
+def _add_positive_jitter(delay: float) -> float:
+ """Add positive jitter (0-20%) to prevent thundering herd."""
+ jitter_multiplier = 1 + random() * JITTER_FACTOR
+ return delay * jitter_multiplier
+
+
+def _add_symmetric_jitter(delay: float) -> float:
+ """Add symmetric jitter (±10%) for exponential backoff."""
+ jitter_multiplier = 1 + (random() - 0.5) * JITTER_FACTOR
+ return delay * jitter_multiplier
+
+
+def _parse_x_ratelimit_reset(response_headers: httpx.Headers) -> typing.Optional[float]:
+ """
+ Parse the X-RateLimit-Reset header (Unix timestamp in seconds).
+ Returns seconds to wait, or None if header is missing/invalid.
+ """
+ reset_time_str = response_headers.get("x-ratelimit-reset")
+ if reset_time_str is None:
+ return None
+
+ try:
+ reset_time = int(reset_time_str)
+ delay = reset_time - time.time()
+ if delay > 0:
+ return delay
+ except (ValueError, TypeError):
+ pass
+
+ return None
+
+
+def _retry_timeout(response: httpx.Response, retries: int) -> float:
+ """
+ Determine the amount of time to wait before retrying a request.
+ This function begins by trying to parse a retry-after header from the response, and then proceeds to use exponential backoff
+ with a jitter to determine the number of seconds to wait.
+ """
+
+ # 1. Check Retry-After header first
+ retry_after = _parse_retry_after(response.headers)
+ if retry_after is not None and retry_after > 0:
+ return min(retry_after, MAX_RETRY_DELAY_SECONDS)
+
+ # 2. Check X-RateLimit-Reset header (with positive jitter)
+ ratelimit_reset = _parse_x_ratelimit_reset(response.headers)
+ if ratelimit_reset is not None:
+ return _add_positive_jitter(min(ratelimit_reset, MAX_RETRY_DELAY_SECONDS))
+
+ # 3. Fall back to exponential backoff (with symmetric jitter)
+ backoff = min(INITIAL_RETRY_DELAY_SECONDS * pow(2.0, retries), MAX_RETRY_DELAY_SECONDS)
+ return _add_symmetric_jitter(backoff)
+
+
+def _should_retry(response: httpx.Response) -> bool:
+ retryable_400s = [429, 408, 409]
+ return response.status_code >= 500 or response.status_code in retryable_400s
+
+
+_SENSITIVE_HEADERS = frozenset(
+ {
+ "authorization",
+ "www-authenticate",
+ "x-api-key",
+ "api-key",
+ "apikey",
+ "x-api-token",
+ "x-auth-token",
+ "auth-token",
+ "cookie",
+ "set-cookie",
+ "proxy-authorization",
+ "proxy-authenticate",
+ "x-csrf-token",
+ "x-xsrf-token",
+ "x-session-token",
+ "x-access-token",
+ }
+)
+
+
+def _redact_headers(headers: typing.Dict[str, str]) -> typing.Dict[str, str]:
+ return {k: ("[REDACTED]" if k.lower() in _SENSITIVE_HEADERS else v) for k, v in headers.items()}
+
+
+def _build_url(base_url: str, path: typing.Optional[str]) -> str:
+ """
+ Build a full URL by joining a base URL with a path.
+
+ This function correctly handles base URLs that contain path prefixes (e.g., tenant-based URLs)
+ by using string concatenation instead of urllib.parse.urljoin(), which would incorrectly
+ strip path components when the path starts with '/'.
+
+ Example:
+ >>> _build_url("https://cloud.example.com/org/tenant/api", "/users")
+ 'https://cloud.example.com/org/tenant/api/users'
+
+ Args:
+ base_url: The base URL, which may contain path prefixes.
+ path: The path to append. Can be None or empty string.
+
+ Returns:
+ The full URL with base_url and path properly joined.
+ """
+ if not path:
+ return base_url
+ return f"{base_url.rstrip('/')}/{path.lstrip('/')}"
+
+
+def _maybe_filter_none_from_multipart_data(
+ data: typing.Optional[typing.Any],
+ request_files: typing.Optional[RequestFiles],
+ force_multipart: typing.Optional[bool],
+) -> typing.Optional[typing.Any]:
+ """
+ Filter None values from data body for multipart/form requests.
+ This prevents httpx from converting None to empty strings in multipart encoding.
+ Only applies when files are present or force_multipart is True.
+ """
+ if data is not None and isinstance(data, typing.Mapping) and (request_files or force_multipart):
+ return remove_none_from_dict(data)
+ return data
+
+
+def remove_omit_from_dict(
+ original: typing.Dict[str, typing.Optional[typing.Any]],
+ omit: typing.Optional[typing.Any],
+) -> typing.Dict[str, typing.Any]:
+ if omit is None:
+ return original
+ new: typing.Dict[str, typing.Any] = {}
+ for key, value in original.items():
+ if value is not omit:
+ new[key] = value
+ return new
+
+
+def maybe_filter_request_body(
+ data: typing.Optional[typing.Any],
+ request_options: typing.Optional[RequestOptions],
+ omit: typing.Optional[typing.Any],
+) -> typing.Optional[typing.Any]:
+ if data is None:
+ return (
+ jsonable_encoder(request_options.get("additional_body_parameters", {})) or {}
+ if request_options is not None
+ else None
+ )
+ elif not isinstance(data, typing.Mapping):
+ data_content = jsonable_encoder(data)
+ else:
+ data_content = {
+ **(jsonable_encoder(remove_omit_from_dict(data, omit))), # type: ignore
+ **(
+ jsonable_encoder(request_options.get("additional_body_parameters", {})) or {}
+ if request_options is not None
+ else {}
+ ),
+ }
+ return data_content
+
+
+# Abstracted out for testing purposes
+def get_request_body(
+ *,
+ json: typing.Optional[typing.Any],
+ data: typing.Optional[typing.Any],
+ request_options: typing.Optional[RequestOptions],
+ omit: typing.Optional[typing.Any],
+) -> typing.Tuple[typing.Optional[typing.Any], typing.Optional[typing.Any]]:
+ json_body = None
+ data_body = None
+ if data is not None:
+ data_body = maybe_filter_request_body(data, request_options, omit)
+ else:
+ # If both data and json are None, we send json data in the event extra properties are specified
+ json_body = maybe_filter_request_body(json, request_options, omit)
+
+ has_additional_body_parameters = bool(
+ request_options is not None and request_options.get("additional_body_parameters")
+ )
+
+ # Only collapse empty dict to None when the body was not explicitly provided
+ # and there are no additional body parameters. This preserves explicit empty
+ # bodies (e.g., when an endpoint has a request body type but all fields are optional).
+ if json_body == {} and json is None and not has_additional_body_parameters:
+ json_body = None
+ if data_body == {} and data is None and not has_additional_body_parameters:
+ data_body = None
+
+ return json_body, data_body
+
+
+class HttpClient:
+ def __init__(
+ self,
+ *,
+ httpx_client: httpx.Client,
+ base_timeout: typing.Callable[[], typing.Optional[float]],
+ base_headers: typing.Callable[[], typing.Dict[str, str]],
+ base_url: typing.Optional[typing.Callable[[], str]] = None,
+ logging_config: typing.Optional[typing.Union[LogConfig, Logger]] = None,
+ ):
+ self.base_url = base_url
+ self.base_timeout = base_timeout
+ self.base_headers = base_headers
+ self.httpx_client = httpx_client
+ self.logger = create_logger(logging_config)
+
+ def get_base_url(self, maybe_base_url: typing.Optional[str]) -> str:
+ base_url = maybe_base_url
+ if self.base_url is not None and base_url is None:
+ base_url = self.base_url()
+
+ if base_url is None:
+ raise ValueError("A base_url is required to make this request, please provide one and try again.")
+ return base_url
+
+ def request(
+ self,
+ path: typing.Optional[str] = None,
+ *,
+ method: str,
+ base_url: typing.Optional[str] = None,
+ params: typing.Optional[typing.Dict[str, typing.Any]] = None,
+ json: typing.Optional[typing.Any] = None,
+ data: typing.Optional[typing.Any] = None,
+ content: typing.Optional[typing.Union[bytes, typing.Iterator[bytes], typing.AsyncIterator[bytes]]] = None,
+ files: typing.Optional[
+ typing.Union[
+ typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]],
+ typing.List[typing.Tuple[str, File]],
+ ]
+ ] = None,
+ headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ retries: int = 0,
+ omit: typing.Optional[typing.Any] = None,
+ force_multipart: typing.Optional[bool] = None,
+ ) -> httpx.Response:
+ base_url = self.get_base_url(base_url)
+ timeout = (
+ request_options.get("timeout_in_seconds")
+ if request_options is not None and request_options.get("timeout_in_seconds") is not None
+ else self.base_timeout()
+ )
+
+ json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
+
+ request_files: typing.Optional[RequestFiles] = (
+ convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
+ if (files is not None and files is not omit and isinstance(files, dict))
+ else None
+ )
+
+ if (request_files is None or len(request_files) == 0) and force_multipart:
+ request_files = FORCE_MULTIPART
+
+ data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart)
+
+ # Compute encoded params separately to avoid passing empty list to httpx
+ # (httpx strips existing query params from URL when params=[] is passed)
+ _encoded_params = encode_query(
+ jsonable_encoder(
+ remove_none_from_dict(
+ remove_omit_from_dict(
+ {
+ **(params if params is not None else {}),
+ **(
+ request_options.get("additional_query_parameters", {}) or {}
+ if request_options is not None
+ else {}
+ ),
+ },
+ omit,
+ )
+ )
+ )
+ )
+
+ _request_url = _build_url(base_url, path)
+ _request_headers = jsonable_encoder(
+ remove_none_from_dict(
+ {
+ **self.base_headers(),
+ **(headers if headers is not None else {}),
+ **(request_options.get("additional_headers", {}) or {} if request_options is not None else {}),
+ }
+ )
+ )
+
+ if self.logger.is_debug():
+ self.logger.debug(
+ "Making HTTP request",
+ method=method,
+ url=_request_url,
+ headers=_redact_headers(_request_headers),
+ has_body=json_body is not None or data_body is not None,
+ )
+
+ response = self.httpx_client.request(
+ method=method,
+ url=_request_url,
+ headers=_request_headers,
+ params=_encoded_params if _encoded_params else None,
+ json=json_body,
+ data=data_body,
+ content=content,
+ files=request_files,
+ timeout=timeout,
+ )
+
+ max_retries: int = request_options.get("max_retries", 2) if request_options is not None else 2
+ if _should_retry(response=response):
+ if retries < max_retries:
+ time.sleep(_retry_timeout(response=response, retries=retries))
+ return self.request(
+ path=path,
+ method=method,
+ base_url=base_url,
+ params=params,
+ json=json,
+ content=content,
+ files=files,
+ headers=headers,
+ request_options=request_options,
+ retries=retries + 1,
+ omit=omit,
+ )
+
+ if self.logger.is_debug():
+ if 200 <= response.status_code < 400:
+ self.logger.debug(
+ "HTTP request succeeded",
+ method=method,
+ url=_request_url,
+ status_code=response.status_code,
+ )
+
+ if self.logger.is_error():
+ if response.status_code >= 400:
+ self.logger.error(
+ "HTTP request failed with error status",
+ method=method,
+ url=_request_url,
+ status_code=response.status_code,
+ )
+
+ return response
+
+ @contextmanager
+ def stream(
+ self,
+ path: typing.Optional[str] = None,
+ *,
+ method: str,
+ base_url: typing.Optional[str] = None,
+ params: typing.Optional[typing.Dict[str, typing.Any]] = None,
+ json: typing.Optional[typing.Any] = None,
+ data: typing.Optional[typing.Any] = None,
+ content: typing.Optional[typing.Union[bytes, typing.Iterator[bytes], typing.AsyncIterator[bytes]]] = None,
+ files: typing.Optional[
+ typing.Union[
+ typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]],
+ typing.List[typing.Tuple[str, File]],
+ ]
+ ] = None,
+ headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ retries: int = 0,
+ omit: typing.Optional[typing.Any] = None,
+ force_multipart: typing.Optional[bool] = None,
+ ) -> typing.Iterator[httpx.Response]:
+ base_url = self.get_base_url(base_url)
+ timeout = (
+ request_options.get("timeout_in_seconds")
+ if request_options is not None and request_options.get("timeout_in_seconds") is not None
+ else self.base_timeout()
+ )
+
+ request_files: typing.Optional[RequestFiles] = (
+ convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
+ if (files is not None and files is not omit and isinstance(files, dict))
+ else None
+ )
+
+ if (request_files is None or len(request_files) == 0) and force_multipart:
+ request_files = FORCE_MULTIPART
+
+ json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
+
+ data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart)
+
+ # Compute encoded params separately to avoid passing empty list to httpx
+ # (httpx strips existing query params from URL when params=[] is passed)
+ _encoded_params = encode_query(
+ jsonable_encoder(
+ remove_none_from_dict(
+ remove_omit_from_dict(
+ {
+ **(params if params is not None else {}),
+ **(
+ request_options.get("additional_query_parameters", {})
+ if request_options is not None
+ else {}
+ ),
+ },
+ omit,
+ )
+ )
+ )
+ )
+
+ _request_url = _build_url(base_url, path)
+ _request_headers = jsonable_encoder(
+ remove_none_from_dict(
+ {
+ **self.base_headers(),
+ **(headers if headers is not None else {}),
+ **(request_options.get("additional_headers", {}) if request_options is not None else {}),
+ }
+ )
+ )
+
+ if self.logger.is_debug():
+ self.logger.debug(
+ "Making streaming HTTP request",
+ method=method,
+ url=_request_url,
+ headers=_redact_headers(_request_headers),
+ )
+
+ with self.httpx_client.stream(
+ method=method,
+ url=_request_url,
+ headers=_request_headers,
+ params=_encoded_params if _encoded_params else None,
+ json=json_body,
+ data=data_body,
+ content=content,
+ files=request_files,
+ timeout=timeout,
+ ) as stream:
+ yield stream
+
+
+class AsyncHttpClient:
+ def __init__(
+ self,
+ *,
+ httpx_client: httpx.AsyncClient,
+ base_timeout: typing.Callable[[], typing.Optional[float]],
+ base_headers: typing.Callable[[], typing.Dict[str, str]],
+ base_url: typing.Optional[typing.Callable[[], str]] = None,
+ async_base_headers: typing.Optional[typing.Callable[[], typing.Awaitable[typing.Dict[str, str]]]] = None,
+ logging_config: typing.Optional[typing.Union[LogConfig, Logger]] = None,
+ ):
+ self.base_url = base_url
+ self.base_timeout = base_timeout
+ self.base_headers = base_headers
+ self.async_base_headers = async_base_headers
+ self.httpx_client = httpx_client
+ self.logger = create_logger(logging_config)
+
+ async def _get_headers(self) -> typing.Dict[str, str]:
+ if self.async_base_headers is not None:
+ return await self.async_base_headers()
+ return self.base_headers()
+
+ def get_base_url(self, maybe_base_url: typing.Optional[str]) -> str:
+ base_url = maybe_base_url
+ if self.base_url is not None and base_url is None:
+ base_url = self.base_url()
+
+ if base_url is None:
+ raise ValueError("A base_url is required to make this request, please provide one and try again.")
+ return base_url
+
+ async def request(
+ self,
+ path: typing.Optional[str] = None,
+ *,
+ method: str,
+ base_url: typing.Optional[str] = None,
+ params: typing.Optional[typing.Dict[str, typing.Any]] = None,
+ json: typing.Optional[typing.Any] = None,
+ data: typing.Optional[typing.Any] = None,
+ content: typing.Optional[typing.Union[bytes, typing.Iterator[bytes], typing.AsyncIterator[bytes]]] = None,
+ files: typing.Optional[
+ typing.Union[
+ typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]],
+ typing.List[typing.Tuple[str, File]],
+ ]
+ ] = None,
+ headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ retries: int = 0,
+ omit: typing.Optional[typing.Any] = None,
+ force_multipart: typing.Optional[bool] = None,
+ ) -> httpx.Response:
+ base_url = self.get_base_url(base_url)
+ timeout = (
+ request_options.get("timeout_in_seconds")
+ if request_options is not None and request_options.get("timeout_in_seconds") is not None
+ else self.base_timeout()
+ )
+
+ request_files: typing.Optional[RequestFiles] = (
+ convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
+ if (files is not None and files is not omit and isinstance(files, dict))
+ else None
+ )
+
+ if (request_files is None or len(request_files) == 0) and force_multipart:
+ request_files = FORCE_MULTIPART
+
+ json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
+
+ data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart)
+
+ # Get headers (supports async token providers)
+ _headers = await self._get_headers()
+
+ # Compute encoded params separately to avoid passing empty list to httpx
+ # (httpx strips existing query params from URL when params=[] is passed)
+ _encoded_params = encode_query(
+ jsonable_encoder(
+ remove_none_from_dict(
+ remove_omit_from_dict(
+ {
+ **(params if params is not None else {}),
+ **(
+ request_options.get("additional_query_parameters", {}) or {}
+ if request_options is not None
+ else {}
+ ),
+ },
+ omit,
+ )
+ )
+ )
+ )
+
+ _request_url = _build_url(base_url, path)
+ _request_headers = jsonable_encoder(
+ remove_none_from_dict(
+ {
+ **_headers,
+ **(headers if headers is not None else {}),
+ **(request_options.get("additional_headers", {}) or {} if request_options is not None else {}),
+ }
+ )
+ )
+
+ if self.logger.is_debug():
+ self.logger.debug(
+ "Making HTTP request",
+ method=method,
+ url=_request_url,
+ headers=_redact_headers(_request_headers),
+ has_body=json_body is not None or data_body is not None,
+ )
+
+ response = await self.httpx_client.request(
+ method=method,
+ url=_request_url,
+ headers=_request_headers,
+ params=_encoded_params if _encoded_params else None,
+ json=json_body,
+ data=data_body,
+ content=content,
+ files=request_files,
+ timeout=timeout,
+ )
+
+ max_retries: int = request_options.get("max_retries", 2) if request_options is not None else 2
+ if _should_retry(response=response):
+ if retries < max_retries:
+ await asyncio.sleep(_retry_timeout(response=response, retries=retries))
+ return await self.request(
+ path=path,
+ method=method,
+ base_url=base_url,
+ params=params,
+ json=json,
+ content=content,
+ files=files,
+ headers=headers,
+ request_options=request_options,
+ retries=retries + 1,
+ omit=omit,
+ )
+
+ if self.logger.is_debug():
+ if 200 <= response.status_code < 400:
+ self.logger.debug(
+ "HTTP request succeeded",
+ method=method,
+ url=_request_url,
+ status_code=response.status_code,
+ )
+
+ if self.logger.is_error():
+ if response.status_code >= 400:
+ self.logger.error(
+ "HTTP request failed with error status",
+ method=method,
+ url=_request_url,
+ status_code=response.status_code,
+ )
+
+ return response
+
+ @asynccontextmanager
+ async def stream(
+ self,
+ path: typing.Optional[str] = None,
+ *,
+ method: str,
+ base_url: typing.Optional[str] = None,
+ params: typing.Optional[typing.Dict[str, typing.Any]] = None,
+ json: typing.Optional[typing.Any] = None,
+ data: typing.Optional[typing.Any] = None,
+ content: typing.Optional[typing.Union[bytes, typing.Iterator[bytes], typing.AsyncIterator[bytes]]] = None,
+ files: typing.Optional[
+ typing.Union[
+ typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]],
+ typing.List[typing.Tuple[str, File]],
+ ]
+ ] = None,
+ headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ retries: int = 0,
+ omit: typing.Optional[typing.Any] = None,
+ force_multipart: typing.Optional[bool] = None,
+ ) -> typing.AsyncIterator[httpx.Response]:
+ base_url = self.get_base_url(base_url)
+ timeout = (
+ request_options.get("timeout_in_seconds")
+ if request_options is not None and request_options.get("timeout_in_seconds") is not None
+ else self.base_timeout()
+ )
+
+ request_files: typing.Optional[RequestFiles] = (
+ convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
+ if (files is not None and files is not omit and isinstance(files, dict))
+ else None
+ )
+
+ if (request_files is None or len(request_files) == 0) and force_multipart:
+ request_files = FORCE_MULTIPART
+
+ json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
+
+ data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart)
+
+ # Get headers (supports async token providers)
+ _headers = await self._get_headers()
+
+ # Compute encoded params separately to avoid passing empty list to httpx
+ # (httpx strips existing query params from URL when params=[] is passed)
+ _encoded_params = encode_query(
+ jsonable_encoder(
+ remove_none_from_dict(
+ remove_omit_from_dict(
+ {
+ **(params if params is not None else {}),
+ **(
+ request_options.get("additional_query_parameters", {})
+ if request_options is not None
+ else {}
+ ),
+ },
+ omit=omit,
+ )
+ )
+ )
+ )
+
+ _request_url = _build_url(base_url, path)
+ _request_headers = jsonable_encoder(
+ remove_none_from_dict(
+ {
+ **_headers,
+ **(headers if headers is not None else {}),
+ **(request_options.get("additional_headers", {}) if request_options is not None else {}),
+ }
+ )
+ )
+
+ if self.logger.is_debug():
+ self.logger.debug(
+ "Making streaming HTTP request",
+ method=method,
+ url=_request_url,
+ headers=_redact_headers(_request_headers),
+ )
+
+ async with self.httpx_client.stream(
+ method=method,
+ url=_request_url,
+ headers=_request_headers,
+ params=_encoded_params if _encoded_params else None,
+ json=json_body,
+ data=data_body,
+ content=content,
+ files=request_files,
+ timeout=timeout,
+ ) as stream:
+ yield stream
diff --git a/src/webflow/core/http_response.py b/src/webflow/core/http_response.py
new file mode 100644
index 0000000..00bb109
--- /dev/null
+++ b/src/webflow/core/http_response.py
@@ -0,0 +1,59 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from typing import Dict, Generic, TypeVar
+
+import httpx
+
+# Generic to represent the underlying type of the data wrapped by the HTTP response.
+T = TypeVar("T")
+
+
+class BaseHttpResponse:
+ """Minimalist HTTP response wrapper that exposes response headers and status code."""
+
+ _response: httpx.Response
+
+ def __init__(self, response: httpx.Response):
+ self._response = response
+
+ @property
+ def headers(self) -> Dict[str, str]:
+ return dict(self._response.headers)
+
+ @property
+ def status_code(self) -> int:
+ return self._response.status_code
+
+
+class HttpResponse(Generic[T], BaseHttpResponse):
+ """HTTP response wrapper that exposes response headers and data."""
+
+ _data: T
+
+ def __init__(self, response: httpx.Response, data: T):
+ super().__init__(response)
+ self._data = data
+
+ @property
+ def data(self) -> T:
+ return self._data
+
+ def close(self) -> None:
+ self._response.close()
+
+
+class AsyncHttpResponse(Generic[T], BaseHttpResponse):
+ """HTTP response wrapper that exposes response headers and data."""
+
+ _data: T
+
+ def __init__(self, response: httpx.Response, data: T):
+ super().__init__(response)
+ self._data = data
+
+ @property
+ def data(self) -> T:
+ return self._data
+
+ async def close(self) -> None:
+ await self._response.aclose()
diff --git a/src/webflow/core/http_sse/__init__.py b/src/webflow/core/http_sse/__init__.py
new file mode 100644
index 0000000..730e5a3
--- /dev/null
+++ b/src/webflow/core/http_sse/__init__.py
@@ -0,0 +1,42 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from ._api import EventSource, aconnect_sse, connect_sse
+ from ._exceptions import SSEError
+ from ._models import ServerSentEvent
+_dynamic_imports: typing.Dict[str, str] = {
+ "EventSource": "._api",
+ "SSEError": "._exceptions",
+ "ServerSentEvent": "._models",
+ "aconnect_sse": "._api",
+ "connect_sse": "._api",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = ["EventSource", "SSEError", "ServerSentEvent", "aconnect_sse", "connect_sse"]
diff --git a/src/webflow/core/http_sse/_api.py b/src/webflow/core/http_sse/_api.py
new file mode 100644
index 0000000..f900b3b
--- /dev/null
+++ b/src/webflow/core/http_sse/_api.py
@@ -0,0 +1,112 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import re
+from contextlib import asynccontextmanager, contextmanager
+from typing import Any, AsyncGenerator, AsyncIterator, Iterator, cast
+
+import httpx
+from ._decoders import SSEDecoder
+from ._exceptions import SSEError
+from ._models import ServerSentEvent
+
+
+class EventSource:
+ def __init__(self, response: httpx.Response) -> None:
+ self._response = response
+
+ def _check_content_type(self) -> None:
+ content_type = self._response.headers.get("content-type", "").partition(";")[0]
+ if "text/event-stream" not in content_type:
+ raise SSEError(
+ f"Expected response header Content-Type to contain 'text/event-stream', got {content_type!r}"
+ )
+
+ def _get_charset(self) -> str:
+ """Extract charset from Content-Type header, fallback to UTF-8."""
+ content_type = self._response.headers.get("content-type", "")
+
+ # Parse charset parameter using regex
+ charset_match = re.search(r"charset=([^;\s]+)", content_type, re.IGNORECASE)
+ if charset_match:
+ charset = charset_match.group(1).strip("\"'")
+ # Validate that it's a known encoding
+ try:
+ # Test if the charset is valid by trying to encode/decode
+ "test".encode(charset).decode(charset)
+ return charset
+ except (LookupError, UnicodeError):
+ # If charset is invalid, fall back to UTF-8
+ pass
+
+ # Default to UTF-8 if no charset specified or invalid charset
+ return "utf-8"
+
+ @property
+ def response(self) -> httpx.Response:
+ return self._response
+
+ def iter_sse(self) -> Iterator[ServerSentEvent]:
+ self._check_content_type()
+ decoder = SSEDecoder()
+ charset = self._get_charset()
+
+ buffer = ""
+ for chunk in self._response.iter_bytes():
+ # Decode chunk using detected charset
+ text_chunk = chunk.decode(charset, errors="replace")
+ buffer += text_chunk
+
+ # Process complete lines
+ while "\n" in buffer:
+ line, buffer = buffer.split("\n", 1)
+ line = line.rstrip("\r")
+ sse = decoder.decode(line)
+ # when we reach a "\n\n" => line = ''
+ # => decoder will attempt to return an SSE Event
+ if sse is not None:
+ yield sse
+
+ # Process any remaining data in buffer
+ if buffer.strip():
+ line = buffer.rstrip("\r")
+ sse = decoder.decode(line)
+ if sse is not None:
+ yield sse
+
+ async def aiter_sse(self) -> AsyncGenerator[ServerSentEvent, None]:
+ self._check_content_type()
+ decoder = SSEDecoder()
+ lines = cast(AsyncGenerator[str, None], self._response.aiter_lines())
+ try:
+ async for line in lines:
+ line = line.rstrip("\n")
+ sse = decoder.decode(line)
+ if sse is not None:
+ yield sse
+ finally:
+ await lines.aclose()
+
+
+@contextmanager
+def connect_sse(client: httpx.Client, method: str, url: str, **kwargs: Any) -> Iterator[EventSource]:
+ headers = kwargs.pop("headers", {})
+ headers["Accept"] = "text/event-stream"
+ headers["Cache-Control"] = "no-store"
+
+ with client.stream(method, url, headers=headers, **kwargs) as response:
+ yield EventSource(response)
+
+
+@asynccontextmanager
+async def aconnect_sse(
+ client: httpx.AsyncClient,
+ method: str,
+ url: str,
+ **kwargs: Any,
+) -> AsyncIterator[EventSource]:
+ headers = kwargs.pop("headers", {})
+ headers["Accept"] = "text/event-stream"
+ headers["Cache-Control"] = "no-store"
+
+ async with client.stream(method, url, headers=headers, **kwargs) as response:
+ yield EventSource(response)
diff --git a/src/webflow/core/http_sse/_decoders.py b/src/webflow/core/http_sse/_decoders.py
new file mode 100644
index 0000000..339b089
--- /dev/null
+++ b/src/webflow/core/http_sse/_decoders.py
@@ -0,0 +1,61 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from typing import List, Optional
+
+from ._models import ServerSentEvent
+
+
+class SSEDecoder:
+ def __init__(self) -> None:
+ self._event = ""
+ self._data: List[str] = []
+ self._last_event_id = ""
+ self._retry: Optional[int] = None
+
+ def decode(self, line: str) -> Optional[ServerSentEvent]:
+ # See: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation # noqa: E501
+
+ if not line:
+ if not self._event and not self._data and not self._last_event_id and self._retry is None:
+ return None
+
+ sse = ServerSentEvent(
+ event=self._event,
+ data="\n".join(self._data),
+ id=self._last_event_id,
+ retry=self._retry,
+ )
+
+ # NOTE: as per the SSE spec, do not reset last_event_id.
+ self._event = ""
+ self._data = []
+ self._retry = None
+
+ return sse
+
+ if line.startswith(":"):
+ return None
+
+ fieldname, _, value = line.partition(":")
+
+ if value.startswith(" "):
+ value = value[1:]
+
+ if fieldname == "event":
+ self._event = value
+ elif fieldname == "data":
+ self._data.append(value)
+ elif fieldname == "id":
+ if "\0" in value:
+ pass
+ else:
+ self._last_event_id = value
+ elif fieldname == "retry":
+ try:
+ self._retry = int(value)
+ except (TypeError, ValueError):
+ pass
+ else:
+ pass # Field is ignored.
+
+ return None
diff --git a/src/webflow/core/http_sse/_exceptions.py b/src/webflow/core/http_sse/_exceptions.py
new file mode 100644
index 0000000..81605a8
--- /dev/null
+++ b/src/webflow/core/http_sse/_exceptions.py
@@ -0,0 +1,7 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import httpx
+
+
+class SSEError(httpx.TransportError):
+ pass
diff --git a/src/webflow/core/http_sse/_models.py b/src/webflow/core/http_sse/_models.py
new file mode 100644
index 0000000..1af57f8
--- /dev/null
+++ b/src/webflow/core/http_sse/_models.py
@@ -0,0 +1,17 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import json
+from dataclasses import dataclass
+from typing import Any, Optional
+
+
+@dataclass(frozen=True)
+class ServerSentEvent:
+ event: str = "message"
+ data: str = ""
+ id: str = ""
+ retry: Optional[int] = None
+
+ def json(self) -> Any:
+ """Parse the data field as JSON."""
+ return json.loads(self.data)
diff --git a/src/webflow/core/jsonable_encoder.py b/src/webflow/core/jsonable_encoder.py
index 37238ab..f8beaea 100644
--- a/src/webflow/core/jsonable_encoder.py
+++ b/src/webflow/core/jsonable_encoder.py
@@ -8,39 +8,32 @@
https://github.com/tiangolo/fastapi/blob/master/fastapi/encoders.py
"""
+import base64
import dataclasses
import datetime as dt
-from collections import defaultdict
from enum import Enum
from pathlib import PurePath
from types import GeneratorType
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+from typing import Any, Callable, Dict, List, Optional, Set, Union
+import pydantic
from .datetime_utils import serialize_datetime
+from .pydantic_utilities import (
+ IS_PYDANTIC_V2,
+ encode_by_type,
+ to_jsonable_with_fallback,
+)
SetIntStr = Set[Union[int, str]]
DictIntStrAny = Dict[Union[int, str], Any]
-def generate_encoders_by_class_tuples(
- type_encoder_map: Dict[Any, Callable[[Any], Any]]
-) -> Dict[Callable[[Any], Any], Tuple[Any, ...]]:
- encoders_by_class_tuples: Dict[Callable[[Any], Any], Tuple[Any, ...]] = defaultdict(tuple)
- for type_, encoder in type_encoder_map.items():
- encoders_by_class_tuples[encoder] += (type_,)
- return encoders_by_class_tuples
-
-
-encoders_by_class_tuples = generate_encoders_by_class_tuples(pydantic.json.ENCODERS_BY_TYPE)
-
-
def jsonable_encoder(obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any], Any]]] = None) -> Any:
custom_encoder = custom_encoder or {}
+ # Generated SDKs use Ellipsis (`...`) as the sentinel value for "OMIT".
+ # OMIT values should be excluded from serialized payloads.
+ if obj is Ellipsis:
+ return None
if custom_encoder:
if type(obj) in custom_encoder:
return custom_encoder[type(obj)](obj)
@@ -49,31 +42,40 @@ def jsonable_encoder(obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any]
if isinstance(obj, encoder_type):
return encoder_instance(obj)
if isinstance(obj, pydantic.BaseModel):
- encoder = getattr(obj.__config__, "json_encoders", {})
+ if IS_PYDANTIC_V2:
+ encoder = getattr(obj.model_config, "json_encoders", {}) # type: ignore # Pydantic v2
+ else:
+ encoder = getattr(obj.__config__, "json_encoders", {}) # type: ignore # Pydantic v1
if custom_encoder:
encoder.update(custom_encoder)
obj_dict = obj.dict(by_alias=True)
if "__root__" in obj_dict:
obj_dict = obj_dict["__root__"]
+ if "root" in obj_dict:
+ obj_dict = obj_dict["root"]
return jsonable_encoder(obj_dict, custom_encoder=encoder)
if dataclasses.is_dataclass(obj):
- obj_dict = dataclasses.asdict(obj)
+ obj_dict = dataclasses.asdict(obj) # type: ignore
return jsonable_encoder(obj_dict, custom_encoder=custom_encoder)
+ if isinstance(obj, bytes):
+ return base64.b64encode(obj).decode("utf-8")
if isinstance(obj, Enum):
return obj.value
if isinstance(obj, PurePath):
return str(obj)
if isinstance(obj, (str, int, float, type(None))):
return obj
- if isinstance(obj, dt.date):
- return str(obj)
if isinstance(obj, dt.datetime):
return serialize_datetime(obj)
+ if isinstance(obj, dt.date):
+ return str(obj)
if isinstance(obj, dict):
encoded_dict = {}
allowed_keys = set(obj.keys())
for key, value in obj.items():
if key in allowed_keys:
+ if value is Ellipsis:
+ continue
encoded_key = jsonable_encoder(key, custom_encoder=custom_encoder)
encoded_value = jsonable_encoder(value, custom_encoder=custom_encoder)
encoded_dict[encoded_key] = encoded_value
@@ -81,23 +83,26 @@ def jsonable_encoder(obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any]
if isinstance(obj, (list, set, frozenset, GeneratorType, tuple)):
encoded_list = []
for item in obj:
+ if item is Ellipsis:
+ continue
encoded_list.append(jsonable_encoder(item, custom_encoder=custom_encoder))
return encoded_list
- if type(obj) in pydantic.json.ENCODERS_BY_TYPE:
- return pydantic.json.ENCODERS_BY_TYPE[type(obj)](obj)
- for encoder, classes_tuple in encoders_by_class_tuples.items():
- if isinstance(obj, classes_tuple):
- return encoder(obj)
+ def fallback_serializer(o: Any) -> Any:
+ attempt_encode = encode_by_type(o)
+ if attempt_encode is not None:
+ return attempt_encode
- try:
- data = dict(obj)
- except Exception as e:
- errors: List[Exception] = []
- errors.append(e)
try:
- data = vars(obj)
+ data = dict(o)
except Exception as e:
+ errors: List[Exception] = []
errors.append(e)
- raise ValueError(errors) from e
- return jsonable_encoder(data, custom_encoder=custom_encoder)
+ try:
+ data = vars(o)
+ except Exception as e:
+ errors.append(e)
+ raise ValueError(errors) from e
+ return jsonable_encoder(data, custom_encoder=custom_encoder)
+
+ return to_jsonable_with_fallback(obj, fallback_serializer)
diff --git a/src/webflow/core/logging.py b/src/webflow/core/logging.py
new file mode 100644
index 0000000..e5e5724
--- /dev/null
+++ b/src/webflow/core/logging.py
@@ -0,0 +1,107 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import logging
+import typing
+
+LogLevel = typing.Literal["debug", "info", "warn", "error"]
+
+_LOG_LEVEL_MAP: typing.Dict[LogLevel, int] = {
+ "debug": 1,
+ "info": 2,
+ "warn": 3,
+ "error": 4,
+}
+
+
+class ILogger(typing.Protocol):
+ def debug(self, message: str, **kwargs: typing.Any) -> None: ...
+ def info(self, message: str, **kwargs: typing.Any) -> None: ...
+ def warn(self, message: str, **kwargs: typing.Any) -> None: ...
+ def error(self, message: str, **kwargs: typing.Any) -> None: ...
+
+
+class ConsoleLogger:
+ _logger: logging.Logger
+
+ def __init__(self) -> None:
+ self._logger = logging.getLogger("fern")
+ if not self._logger.handlers:
+ handler = logging.StreamHandler()
+ handler.setFormatter(logging.Formatter("%(levelname)s - %(message)s"))
+ self._logger.addHandler(handler)
+ self._logger.setLevel(logging.DEBUG)
+
+ def debug(self, message: str, **kwargs: typing.Any) -> None:
+ self._logger.debug(message, extra=kwargs)
+
+ def info(self, message: str, **kwargs: typing.Any) -> None:
+ self._logger.info(message, extra=kwargs)
+
+ def warn(self, message: str, **kwargs: typing.Any) -> None:
+ self._logger.warning(message, extra=kwargs)
+
+ def error(self, message: str, **kwargs: typing.Any) -> None:
+ self._logger.error(message, extra=kwargs)
+
+
+class LogConfig(typing.TypedDict, total=False):
+ level: LogLevel
+ logger: ILogger
+ silent: bool
+
+
+class Logger:
+ _level: int
+ _logger: ILogger
+ _silent: bool
+
+ def __init__(self, *, level: LogLevel, logger: ILogger, silent: bool) -> None:
+ self._level = _LOG_LEVEL_MAP[level]
+ self._logger = logger
+ self._silent = silent
+
+ def _should_log(self, level: LogLevel) -> bool:
+ return not self._silent and self._level <= _LOG_LEVEL_MAP[level]
+
+ def is_debug(self) -> bool:
+ return self._should_log("debug")
+
+ def is_info(self) -> bool:
+ return self._should_log("info")
+
+ def is_warn(self) -> bool:
+ return self._should_log("warn")
+
+ def is_error(self) -> bool:
+ return self._should_log("error")
+
+ def debug(self, message: str, **kwargs: typing.Any) -> None:
+ if self.is_debug():
+ self._logger.debug(message, **kwargs)
+
+ def info(self, message: str, **kwargs: typing.Any) -> None:
+ if self.is_info():
+ self._logger.info(message, **kwargs)
+
+ def warn(self, message: str, **kwargs: typing.Any) -> None:
+ if self.is_warn():
+ self._logger.warn(message, **kwargs)
+
+ def error(self, message: str, **kwargs: typing.Any) -> None:
+ if self.is_error():
+ self._logger.error(message, **kwargs)
+
+
+_default_logger: Logger = Logger(level="info", logger=ConsoleLogger(), silent=True)
+
+
+def create_logger(config: typing.Optional[typing.Union[LogConfig, Logger]] = None) -> Logger:
+ if config is None:
+ return _default_logger
+ if isinstance(config, Logger):
+ return config
+ return Logger(
+ level=config.get("level", "info"),
+ logger=config.get("logger", ConsoleLogger()),
+ silent=config.get("silent", True),
+ )
diff --git a/src/webflow/core/parse_error.py b/src/webflow/core/parse_error.py
new file mode 100644
index 0000000..4527c6a
--- /dev/null
+++ b/src/webflow/core/parse_error.py
@@ -0,0 +1,36 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from typing import Any, Dict, Optional
+
+
+class ParsingError(Exception):
+ """
+ Raised when the SDK fails to parse/validate a response from the server.
+ This typically indicates that the server returned a response whose shape
+ does not match the expected schema.
+ """
+
+ headers: Optional[Dict[str, str]]
+ status_code: Optional[int]
+ body: Any
+ cause: Optional[Exception]
+
+ def __init__(
+ self,
+ *,
+ headers: Optional[Dict[str, str]] = None,
+ status_code: Optional[int] = None,
+ body: Any = None,
+ cause: Optional[Exception] = None,
+ ) -> None:
+ self.headers = headers
+ self.status_code = status_code
+ self.body = body
+ self.cause = cause
+ super().__init__()
+ if cause is not None:
+ self.__cause__ = cause
+
+ def __str__(self) -> str:
+ cause_str = f", cause: {self.cause}" if self.cause is not None else ""
+ return f"headers: {self.headers}, status_code: {self.status_code}, body: {self.body}{cause_str}"
diff --git a/src/webflow/core/pydantic_utilities.py b/src/webflow/core/pydantic_utilities.py
new file mode 100644
index 0000000..831aadc
--- /dev/null
+++ b/src/webflow/core/pydantic_utilities.py
@@ -0,0 +1,577 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# nopycln: file
+import datetime as dt
+import inspect
+import json
+import logging
+from collections import defaultdict
+from dataclasses import asdict
+from typing import (
+ TYPE_CHECKING,
+ Any,
+ Callable,
+ ClassVar,
+ Dict,
+ List,
+ Mapping,
+ Optional,
+ Set,
+ Tuple,
+ Type,
+ TypeVar,
+ Union,
+ cast,
+)
+
+import pydantic
+import typing_extensions
+
+_logger = logging.getLogger(__name__)
+
+if TYPE_CHECKING:
+ from .http_sse._models import ServerSentEvent
+
+IS_PYDANTIC_V2 = pydantic.VERSION.startswith("2.")
+
+if IS_PYDANTIC_V2:
+ import warnings
+
+ _datetime_adapter = pydantic.TypeAdapter(dt.datetime) # type: ignore[attr-defined]
+ _date_adapter = pydantic.TypeAdapter(dt.date) # type: ignore[attr-defined]
+
+ def parse_datetime(value: Any) -> dt.datetime: # type: ignore[misc]
+ if isinstance(value, dt.datetime):
+ return value
+ return _datetime_adapter.validate_python(value)
+
+ def parse_date(value: Any) -> dt.date: # type: ignore[misc]
+ if isinstance(value, dt.datetime):
+ return value.date()
+ if isinstance(value, dt.date):
+ return value
+ return _date_adapter.validate_python(value)
+
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore", UserWarning)
+ from pydantic.v1.fields import ModelField as ModelField
+ from pydantic.v1.json import ENCODERS_BY_TYPE as encoders_by_type # type: ignore[attr-defined]
+ from pydantic.v1.typing import get_args as get_args
+ from pydantic.v1.typing import get_origin as get_origin
+ from pydantic.v1.typing import is_literal_type as is_literal_type
+ from pydantic.v1.typing import is_union as is_union
+else:
+ from pydantic.datetime_parse import parse_date as parse_date # type: ignore[no-redef]
+ from pydantic.datetime_parse import parse_datetime as parse_datetime # type: ignore[no-redef]
+ from pydantic.fields import ModelField as ModelField # type: ignore[attr-defined, no-redef]
+ from pydantic.json import ENCODERS_BY_TYPE as encoders_by_type # type: ignore[no-redef]
+ from pydantic.typing import get_args as get_args # type: ignore[no-redef]
+ from pydantic.typing import get_origin as get_origin # type: ignore[no-redef]
+ from pydantic.typing import is_literal_type as is_literal_type # type: ignore[no-redef]
+ from pydantic.typing import is_union as is_union # type: ignore[no-redef]
+
+from .datetime_utils import serialize_datetime
+from .serialization import convert_and_respect_annotation_metadata
+from typing_extensions import TypeAlias
+
+T = TypeVar("T")
+Model = TypeVar("Model", bound=pydantic.BaseModel)
+
+
+def _get_discriminator_and_variants(type_: Type[Any]) -> Tuple[Optional[str], Optional[List[Type[Any]]]]:
+ """
+ Extract the discriminator field name and union variants from a discriminated union type.
+ Supports Annotated[Union[...], Field(discriminator=...)] patterns.
+ Returns (discriminator, variants) or (None, None) if not a discriminated union.
+ """
+ origin = typing_extensions.get_origin(type_)
+
+ if origin is typing_extensions.Annotated:
+ args = typing_extensions.get_args(type_)
+ if len(args) >= 2:
+ inner_type = args[0]
+ # Check annotations for discriminator
+ discriminator = None
+ for annotation in args[1:]:
+ if hasattr(annotation, "discriminator"):
+ discriminator = getattr(annotation, "discriminator", None)
+ break
+
+ if discriminator:
+ inner_origin = typing_extensions.get_origin(inner_type)
+ if inner_origin is Union:
+ variants = list(typing_extensions.get_args(inner_type))
+ return discriminator, variants
+ return None, None
+
+
+def _get_field_annotation(model: Type[Any], field_name: str) -> Optional[Type[Any]]:
+ """Get the type annotation of a field from a Pydantic model."""
+ if IS_PYDANTIC_V2:
+ fields = getattr(model, "model_fields", {})
+ field_info = fields.get(field_name)
+ if field_info:
+ return cast(Optional[Type[Any]], field_info.annotation)
+ else:
+ fields = getattr(model, "__fields__", {})
+ field_info = fields.get(field_name)
+ if field_info:
+ return cast(Optional[Type[Any]], field_info.outer_type_)
+ return None
+
+
+def _find_variant_by_discriminator(
+ variants: List[Type[Any]],
+ discriminator: str,
+ discriminator_value: Any,
+) -> Optional[Type[Any]]:
+ """Find the union variant that matches the discriminator value."""
+ for variant in variants:
+ if not (inspect.isclass(variant) and issubclass(variant, pydantic.BaseModel)):
+ continue
+
+ disc_annotation = _get_field_annotation(variant, discriminator)
+ if disc_annotation and is_literal_type(disc_annotation):
+ literal_args = get_args(disc_annotation)
+ if literal_args and literal_args[0] == discriminator_value:
+ return variant
+ return None
+
+
+def _is_string_type(type_: Type[Any]) -> bool:
+ """Check if a type is str or Optional[str]."""
+ if type_ is str:
+ return True
+
+ origin = typing_extensions.get_origin(type_)
+ if origin is Union:
+ args = typing_extensions.get_args(type_)
+ # Optional[str] = Union[str, None]
+ non_none_args = [a for a in args if a is not type(None)]
+ if len(non_none_args) == 1 and non_none_args[0] is str:
+ return True
+
+ return False
+
+
+def parse_sse_obj(sse: "ServerSentEvent", type_: Type[T]) -> T:
+ """
+ Parse a ServerSentEvent into the appropriate type.
+
+ Handles two scenarios based on where the discriminator field is located:
+
+ 1. Data-level discrimination: The discriminator (e.g., 'type') is inside the 'data' payload.
+ The union describes the data content, not the SSE envelope.
+ -> Returns: json.loads(data) parsed into the type
+
+ Example: ChatStreamResponse with discriminator='type'
+ Input: ServerSentEvent(event="message", data='{"type": "content-delta", ...}', id="")
+ Output: ContentDeltaEvent (parsed from data, SSE envelope stripped)
+
+ 2. Event-level discrimination: The discriminator (e.g., 'event') is at the SSE event level.
+ The union describes the full SSE event structure.
+ -> Returns: SSE envelope with 'data' field JSON-parsed only if the variant expects non-string
+
+ Example: JobStreamResponse with discriminator='event'
+ Input: ServerSentEvent(event="ERROR", data='{"code": "FAILED", ...}', id="123")
+ Output: JobStreamResponse_Error with data as ErrorData object
+
+ But for variants where data is str (like STATUS_UPDATE):
+ Input: ServerSentEvent(event="STATUS_UPDATE", data='{"status": "processing"}', id="1")
+ Output: JobStreamResponse_StatusUpdate with data as string (not parsed)
+
+ Args:
+ sse: The ServerSentEvent object to parse
+ type_: The target discriminated union type
+
+ Returns:
+ The parsed object of type T
+
+ Note:
+ This function is only available in SDK contexts where http_sse module exists.
+ """
+ sse_event = asdict(sse)
+ discriminator, variants = _get_discriminator_and_variants(type_)
+
+ if discriminator is None or variants is None:
+ # Not a discriminated union - parse the data field as JSON
+ data_value = sse_event.get("data")
+ if isinstance(data_value, str) and data_value:
+ try:
+ parsed_data = json.loads(data_value)
+ return parse_obj_as(type_, parsed_data)
+ except json.JSONDecodeError as e:
+ _logger.warning(
+ "Failed to parse SSE data field as JSON: %s, data: %s",
+ e,
+ data_value[:100] if len(data_value) > 100 else data_value,
+ )
+ return parse_obj_as(type_, sse_event)
+
+ data_value = sse_event.get("data")
+
+ # Check if discriminator is at the top level (event-level discrimination)
+ if discriminator in sse_event:
+ # Case 2: Event-level discrimination
+ # Find the matching variant to check if 'data' field needs JSON parsing
+ disc_value = sse_event.get(discriminator)
+ matching_variant = _find_variant_by_discriminator(variants, discriminator, disc_value)
+
+ if matching_variant is not None:
+ # Check what type the variant expects for 'data'
+ data_type = _get_field_annotation(matching_variant, "data")
+ if data_type is not None and not _is_string_type(data_type):
+ # Variant expects non-string data - parse JSON
+ if isinstance(data_value, str) and data_value:
+ try:
+ parsed_data = json.loads(data_value)
+ new_object = dict(sse_event)
+ new_object["data"] = parsed_data
+ return parse_obj_as(type_, new_object)
+ except json.JSONDecodeError as e:
+ _logger.warning(
+ "Failed to parse SSE data field as JSON for event-level discrimination: %s, data: %s",
+ e,
+ data_value[:100] if len(data_value) > 100 else data_value,
+ )
+ # Either no matching variant, data is string type, or JSON parse failed
+ return parse_obj_as(type_, sse_event)
+
+ else:
+ # Case 1: Data-level discrimination
+ # The discriminator is inside the data payload - extract and parse data only
+ if isinstance(data_value, str) and data_value:
+ try:
+ parsed_data = json.loads(data_value)
+ return parse_obj_as(type_, parsed_data)
+ except json.JSONDecodeError as e:
+ _logger.warning(
+ "Failed to parse SSE data field as JSON for data-level discrimination: %s, data: %s",
+ e,
+ data_value[:100] if len(data_value) > 100 else data_value,
+ )
+ return parse_obj_as(type_, sse_event)
+
+
+def parse_obj_as(type_: Type[T], object_: Any) -> T:
+ # convert_and_respect_annotation_metadata is required for TypedDict aliasing.
+ #
+ # For Pydantic models, whether we should pre-dealias depends on how the model encodes aliasing:
+ # - If the model uses real Pydantic aliases (pydantic.Field(alias=...)), then we must pass wire keys through
+ # unchanged so Pydantic can validate them.
+ # - If the model encodes aliasing only via FieldMetadata annotations, then we MUST pre-dealias because Pydantic
+ # will not recognize those aliases during validation.
+ if inspect.isclass(type_) and issubclass(type_, pydantic.BaseModel):
+ has_pydantic_aliases = False
+ if IS_PYDANTIC_V2:
+ for field_name, field_info in getattr(type_, "model_fields", {}).items(): # type: ignore[attr-defined]
+ alias = getattr(field_info, "alias", None)
+ if alias is not None and alias != field_name:
+ has_pydantic_aliases = True
+ break
+ else:
+ for field in getattr(type_, "__fields__", {}).values():
+ alias = getattr(field, "alias", None)
+ name = getattr(field, "name", None)
+ if alias is not None and name is not None and alias != name:
+ has_pydantic_aliases = True
+ break
+
+ dealiased_object = (
+ object_
+ if has_pydantic_aliases
+ else convert_and_respect_annotation_metadata(object_=object_, annotation=type_, direction="read")
+ )
+ else:
+ dealiased_object = convert_and_respect_annotation_metadata(object_=object_, annotation=type_, direction="read")
+ if IS_PYDANTIC_V2:
+ adapter = pydantic.TypeAdapter(type_) # type: ignore[attr-defined]
+ return adapter.validate_python(dealiased_object)
+ return pydantic.parse_obj_as(type_, dealiased_object)
+
+
+def to_jsonable_with_fallback(obj: Any, fallback_serializer: Callable[[Any], Any]) -> Any:
+ if IS_PYDANTIC_V2:
+ from pydantic_core import to_jsonable_python
+
+ return to_jsonable_python(obj, fallback=fallback_serializer)
+ return fallback_serializer(obj)
+
+
+class UniversalBaseModel(pydantic.BaseModel):
+ if IS_PYDANTIC_V2:
+ model_config: ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( # type: ignore[typeddict-unknown-key]
+ # Allow fields beginning with `model_` to be used in the model
+ protected_namespaces=(),
+ )
+
+ @pydantic.model_validator(mode="before") # type: ignore[attr-defined]
+ @classmethod
+ def _coerce_field_names_to_aliases(cls, data: Any) -> Any:
+ """
+ Accept Python field names in input by rewriting them to their Pydantic aliases,
+ while avoiding silent collisions when a key could refer to multiple fields.
+ """
+ if not isinstance(data, Mapping):
+ return data
+
+ fields = getattr(cls, "model_fields", {}) # type: ignore[attr-defined]
+ name_to_alias: Dict[str, str] = {}
+ alias_to_name: Dict[str, str] = {}
+
+ for name, field_info in fields.items():
+ alias = getattr(field_info, "alias", None) or name
+ name_to_alias[name] = alias
+ if alias != name:
+ alias_to_name[alias] = name
+
+ # Detect ambiguous keys: a key that is an alias for one field and a name for another.
+ ambiguous_keys = set(alias_to_name.keys()).intersection(set(name_to_alias.keys()))
+ for key in ambiguous_keys:
+ if key in data and name_to_alias[key] not in data:
+ raise ValueError(
+ f"Ambiguous input key '{key}': it is both a field name and an alias. "
+ "Provide the explicit alias key to disambiguate."
+ )
+
+ original_keys = set(data.keys())
+ rewritten: Dict[str, Any] = dict(data)
+ for name, alias in name_to_alias.items():
+ if alias != name and name in original_keys and alias not in rewritten:
+ rewritten[alias] = rewritten.pop(name)
+
+ return rewritten
+
+ @pydantic.model_serializer(mode="plain", when_used="json") # type: ignore[attr-defined]
+ def serialize_model(self) -> Any: # type: ignore[name-defined]
+ serialized = self.dict() # type: ignore[attr-defined]
+ data = {k: serialize_datetime(v) if isinstance(v, dt.datetime) else v for k, v in serialized.items()}
+ return data
+
+ else:
+
+ class Config:
+ smart_union = True
+ json_encoders = {dt.datetime: serialize_datetime}
+
+ @pydantic.root_validator(pre=True)
+ def _coerce_field_names_to_aliases(cls, values: Any) -> Any:
+ """
+ Pydantic v1 equivalent of _coerce_field_names_to_aliases.
+ """
+ if not isinstance(values, Mapping):
+ return values
+
+ fields = getattr(cls, "__fields__", {})
+ name_to_alias: Dict[str, str] = {}
+ alias_to_name: Dict[str, str] = {}
+
+ for name, field in fields.items():
+ alias = getattr(field, "alias", None) or name
+ name_to_alias[name] = alias
+ if alias != name:
+ alias_to_name[alias] = name
+
+ ambiguous_keys = set(alias_to_name.keys()).intersection(set(name_to_alias.keys()))
+ for key in ambiguous_keys:
+ if key in values and name_to_alias[key] not in values:
+ raise ValueError(
+ f"Ambiguous input key '{key}': it is both a field name and an alias. "
+ "Provide the explicit alias key to disambiguate."
+ )
+
+ original_keys = set(values.keys())
+ rewritten: Dict[str, Any] = dict(values)
+ for name, alias in name_to_alias.items():
+ if alias != name and name in original_keys and alias not in rewritten:
+ rewritten[alias] = rewritten.pop(name)
+
+ return rewritten
+
+ @classmethod
+ def model_construct(cls: Type["Model"], _fields_set: Optional[Set[str]] = None, **values: Any) -> "Model":
+ dealiased_object = convert_and_respect_annotation_metadata(object_=values, annotation=cls, direction="read")
+ return cls.construct(_fields_set, **dealiased_object)
+
+ @classmethod
+ def construct(cls: Type["Model"], _fields_set: Optional[Set[str]] = None, **values: Any) -> "Model":
+ dealiased_object = convert_and_respect_annotation_metadata(object_=values, annotation=cls, direction="read")
+ if IS_PYDANTIC_V2:
+ return super().model_construct(_fields_set, **dealiased_object) # type: ignore[misc]
+ return super().construct(_fields_set, **dealiased_object)
+
+ def json(self, **kwargs: Any) -> str:
+ kwargs_with_defaults = {
+ "by_alias": True,
+ "exclude_unset": True,
+ **kwargs,
+ }
+ if IS_PYDANTIC_V2:
+ return super().model_dump_json(**kwargs_with_defaults) # type: ignore[misc]
+ return super().json(**kwargs_with_defaults)
+
+ def dict(self, **kwargs: Any) -> Dict[str, Any]:
+ """
+ Override the default dict method to `exclude_unset` by default. This function patches
+ `exclude_unset` to work include fields within non-None default values.
+ """
+ # Note: the logic here is multiplexed given the levers exposed in Pydantic V1 vs V2
+ # Pydantic V1's .dict can be extremely slow, so we do not want to call it twice.
+ #
+ # We'd ideally do the same for Pydantic V2, but it shells out to a library to serialize models
+ # that we have less control over, and this is less intrusive than custom serializers for now.
+ if IS_PYDANTIC_V2:
+ kwargs_with_defaults_exclude_unset = {
+ **kwargs,
+ "by_alias": True,
+ "exclude_unset": True,
+ "exclude_none": False,
+ }
+ kwargs_with_defaults_exclude_none = {
+ **kwargs,
+ "by_alias": True,
+ "exclude_none": True,
+ "exclude_unset": False,
+ }
+ dict_dump = deep_union_pydantic_dicts(
+ super().model_dump(**kwargs_with_defaults_exclude_unset), # type: ignore[misc]
+ super().model_dump(**kwargs_with_defaults_exclude_none), # type: ignore[misc]
+ )
+
+ else:
+ _fields_set = self.__fields_set__.copy()
+
+ fields = _get_model_fields(self.__class__)
+ for name, field in fields.items():
+ if name not in _fields_set:
+ default = _get_field_default(field)
+
+ # If the default values are non-null act like they've been set
+ # This effectively allows exclude_unset to work like exclude_none where
+ # the latter passes through intentionally set none values.
+ if default is not None or ("exclude_unset" in kwargs and not kwargs["exclude_unset"]):
+ _fields_set.add(name)
+
+ if default is not None:
+ self.__fields_set__.add(name)
+
+ kwargs_with_defaults_exclude_unset_include_fields = {
+ "by_alias": True,
+ "exclude_unset": True,
+ "include": _fields_set,
+ **kwargs,
+ }
+
+ dict_dump = super().dict(**kwargs_with_defaults_exclude_unset_include_fields)
+
+ return cast(
+ Dict[str, Any],
+ convert_and_respect_annotation_metadata(object_=dict_dump, annotation=self.__class__, direction="write"),
+ )
+
+
+def _union_list_of_pydantic_dicts(source: List[Any], destination: List[Any]) -> List[Any]:
+ converted_list: List[Any] = []
+ for i, item in enumerate(source):
+ destination_value = destination[i]
+ if isinstance(item, dict):
+ converted_list.append(deep_union_pydantic_dicts(item, destination_value))
+ elif isinstance(item, list):
+ converted_list.append(_union_list_of_pydantic_dicts(item, destination_value))
+ else:
+ converted_list.append(item)
+ return converted_list
+
+
+def deep_union_pydantic_dicts(source: Dict[str, Any], destination: Dict[str, Any]) -> Dict[str, Any]:
+ for key, value in source.items():
+ node = destination.setdefault(key, {})
+ if isinstance(value, dict):
+ deep_union_pydantic_dicts(value, node)
+ # Note: we do not do this same processing for sets given we do not have sets of models
+ # and given the sets are unordered, the processing of the set and matching objects would
+ # be non-trivial.
+ elif isinstance(value, list):
+ destination[key] = _union_list_of_pydantic_dicts(value, node)
+ else:
+ destination[key] = value
+
+ return destination
+
+
+if IS_PYDANTIC_V2:
+
+ class V2RootModel(UniversalBaseModel, pydantic.RootModel): # type: ignore[misc, name-defined, type-arg]
+ pass
+
+ UniversalRootModel: TypeAlias = V2RootModel # type: ignore[misc]
+else:
+ UniversalRootModel: TypeAlias = UniversalBaseModel # type: ignore[misc, no-redef]
+
+
+def encode_by_type(o: Any) -> Any:
+ encoders_by_class_tuples: Dict[Callable[[Any], Any], Tuple[Any, ...]] = defaultdict(tuple)
+ for type_, encoder in encoders_by_type.items():
+ encoders_by_class_tuples[encoder] += (type_,)
+
+ if type(o) in encoders_by_type:
+ return encoders_by_type[type(o)](o)
+ for encoder, classes_tuple in encoders_by_class_tuples.items():
+ if isinstance(o, classes_tuple):
+ return encoder(o)
+
+
+def update_forward_refs(model: Type["Model"], **localns: Any) -> None:
+ if IS_PYDANTIC_V2:
+ model.model_rebuild(raise_errors=False) # type: ignore[attr-defined]
+ else:
+ model.update_forward_refs(**localns)
+
+
+# Mirrors Pydantic's internal typing
+AnyCallable = Callable[..., Any]
+
+
+def universal_root_validator(
+ pre: bool = False,
+) -> Callable[[AnyCallable], AnyCallable]:
+ def decorator(func: AnyCallable) -> AnyCallable:
+ if IS_PYDANTIC_V2:
+ # In Pydantic v2, for RootModel we always use "before" mode
+ # The custom validators transform the input value before the model is created
+ return cast(AnyCallable, pydantic.model_validator(mode="before")(func)) # type: ignore[attr-defined]
+ return cast(AnyCallable, pydantic.root_validator(pre=pre)(func)) # type: ignore[call-overload]
+
+ return decorator
+
+
+def universal_field_validator(field_name: str, pre: bool = False) -> Callable[[AnyCallable], AnyCallable]:
+ def decorator(func: AnyCallable) -> AnyCallable:
+ if IS_PYDANTIC_V2:
+ return cast(AnyCallable, pydantic.field_validator(field_name, mode="before" if pre else "after")(func)) # type: ignore[attr-defined]
+ return cast(AnyCallable, pydantic.validator(field_name, pre=pre)(func))
+
+ return decorator
+
+
+PydanticField = Union[ModelField, pydantic.fields.FieldInfo]
+
+
+def _get_model_fields(model: Type["Model"]) -> Mapping[str, PydanticField]:
+ if IS_PYDANTIC_V2:
+ return cast(Mapping[str, PydanticField], model.model_fields) # type: ignore[attr-defined]
+ return cast(Mapping[str, PydanticField], model.__fields__)
+
+
+def _get_field_default(field: PydanticField) -> Any:
+ try:
+ value = field.get_default() # type: ignore[union-attr]
+ except:
+ value = field.default
+ if IS_PYDANTIC_V2:
+ from pydantic_core import PydanticUndefined
+
+ if value == PydanticUndefined:
+ return None
+ return value
+ return value
diff --git a/src/webflow/core/query_encoder.py b/src/webflow/core/query_encoder.py
new file mode 100644
index 0000000..3183001
--- /dev/null
+++ b/src/webflow/core/query_encoder.py
@@ -0,0 +1,58 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from typing import Any, Dict, List, Optional, Tuple
+
+import pydantic
+
+
+# Flattens dicts to be of the form {"key[subkey][subkey2]": value} where value is not a dict
+def traverse_query_dict(dict_flat: Dict[str, Any], key_prefix: Optional[str] = None) -> List[Tuple[str, Any]]:
+ result = []
+ for k, v in dict_flat.items():
+ key = f"{key_prefix}[{k}]" if key_prefix is not None else k
+ if isinstance(v, dict):
+ result.extend(traverse_query_dict(v, key))
+ elif isinstance(v, list):
+ for arr_v in v:
+ if isinstance(arr_v, dict):
+ result.extend(traverse_query_dict(arr_v, key))
+ else:
+ result.append((key, arr_v))
+ else:
+ result.append((key, v))
+ return result
+
+
+def single_query_encoder(query_key: str, query_value: Any) -> List[Tuple[str, Any]]:
+ if isinstance(query_value, pydantic.BaseModel) or isinstance(query_value, dict):
+ if isinstance(query_value, pydantic.BaseModel):
+ obj_dict = query_value.dict(by_alias=True)
+ else:
+ obj_dict = query_value
+ return traverse_query_dict(obj_dict, query_key)
+ elif isinstance(query_value, list):
+ encoded_values: List[Tuple[str, Any]] = []
+ for value in query_value:
+ if isinstance(value, pydantic.BaseModel) or isinstance(value, dict):
+ if isinstance(value, pydantic.BaseModel):
+ obj_dict = value.dict(by_alias=True)
+ elif isinstance(value, dict):
+ obj_dict = value
+
+ encoded_values.extend(single_query_encoder(query_key, obj_dict))
+ else:
+ encoded_values.append((query_key, value))
+
+ return encoded_values
+
+ return [(query_key, query_value)]
+
+
+def encode_query(query: Optional[Dict[str, Any]]) -> Optional[List[Tuple[str, Any]]]:
+ if query is None:
+ return None
+
+ encoded_query = []
+ for k, v in query.items():
+ encoded_query.extend(single_query_encoder(k, v))
+ return encoded_query
diff --git a/src/webflow/core/remove_none_from_dict.py b/src/webflow/core/remove_none_from_dict.py
index 2da30f7..c229814 100644
--- a/src/webflow/core/remove_none_from_dict.py
+++ b/src/webflow/core/remove_none_from_dict.py
@@ -1,9 +1,9 @@
# This file was auto-generated by Fern from our API Definition.
-from typing import Any, Dict, Optional
+from typing import Any, Dict, Mapping, Optional
-def remove_none_from_dict(original: Dict[str, Optional[Any]]) -> Dict[str, Any]:
+def remove_none_from_dict(original: Mapping[str, Optional[Any]]) -> Dict[str, Any]:
new: Dict[str, Any] = {}
for key, value in original.items():
if value is not None:
diff --git a/src/webflow/core/request_options.py b/src/webflow/core/request_options.py
index 32e86b0..1b38804 100644
--- a/src/webflow/core/request_options.py
+++ b/src/webflow/core/request_options.py
@@ -5,10 +5,10 @@
try:
from typing import NotRequired # type: ignore
except ImportError:
- from typing_extensions import NotRequired # type: ignore
+ from typing_extensions import NotRequired
-class RequestOptions(typing.TypedDict):
+class RequestOptions(typing.TypedDict, total=False):
"""
Additional options for request-specific configuration when calling APIs via the SDK.
This is used primarily as an optional final parameter for service functions.
@@ -16,14 +16,20 @@ class RequestOptions(typing.TypedDict):
Attributes:
- timeout_in_seconds: int. The number of seconds to await an API call before timing out.
+ - max_retries: int. The max number of retries to attempt if the API call fails.
+
- additional_headers: typing.Dict[str, typing.Any]. A dictionary containing additional parameters to spread into the request's header dict
- additional_query_parameters: typing.Dict[str, typing.Any]. A dictionary containing additional parameters to spread into the request's query parameters dict
- additional_body_parameters: typing.Dict[str, typing.Any]. A dictionary containing additional parameters to spread into the request's body parameters dict
+
+ - chunk_size: int. The size, in bytes, to process each chunk of data being streamed back within the response. This equates to leveraging `chunk_size` within `requests` or `httpx`, and is only leveraged for file downloads.
"""
timeout_in_seconds: NotRequired[int]
+ max_retries: NotRequired[int]
additional_headers: NotRequired[typing.Dict[str, typing.Any]]
additional_query_parameters: NotRequired[typing.Dict[str, typing.Any]]
additional_body_parameters: NotRequired[typing.Dict[str, typing.Any]]
+ chunk_size: NotRequired[int]
diff --git a/src/webflow/core/serialization.py b/src/webflow/core/serialization.py
new file mode 100644
index 0000000..c36e865
--- /dev/null
+++ b/src/webflow/core/serialization.py
@@ -0,0 +1,276 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import collections
+import inspect
+import typing
+
+import pydantic
+import typing_extensions
+
+
+class FieldMetadata:
+ """
+ Metadata class used to annotate fields to provide additional information.
+
+ Example:
+ class MyDict(TypedDict):
+ field: typing.Annotated[str, FieldMetadata(alias="field_name")]
+
+ Will serialize: `{"field": "value"}`
+ To: `{"field_name": "value"}`
+ """
+
+ alias: str
+
+ def __init__(self, *, alias: str) -> None:
+ self.alias = alias
+
+
+def convert_and_respect_annotation_metadata(
+ *,
+ object_: typing.Any,
+ annotation: typing.Any,
+ inner_type: typing.Optional[typing.Any] = None,
+ direction: typing.Literal["read", "write"],
+) -> typing.Any:
+ """
+ Respect the metadata annotations on a field, such as aliasing. This function effectively
+ manipulates the dict-form of an object to respect the metadata annotations. This is primarily used for
+ TypedDicts, which cannot support aliasing out of the box, and can be extended for additional
+ utilities, such as defaults.
+
+ Parameters
+ ----------
+ object_ : typing.Any
+
+ annotation : type
+ The type we're looking to apply typing annotations from
+
+ inner_type : typing.Optional[type]
+
+ Returns
+ -------
+ typing.Any
+ """
+
+ if object_ is None:
+ return None
+ if inner_type is None:
+ inner_type = annotation
+
+ clean_type = _remove_annotations(inner_type)
+ # Pydantic models
+ if (
+ inspect.isclass(clean_type)
+ and issubclass(clean_type, pydantic.BaseModel)
+ and isinstance(object_, typing.Mapping)
+ ):
+ return _convert_mapping(object_, clean_type, direction)
+ # TypedDicts
+ if typing_extensions.is_typeddict(clean_type) and isinstance(object_, typing.Mapping):
+ return _convert_mapping(object_, clean_type, direction)
+
+ if (
+ typing_extensions.get_origin(clean_type) == typing.Dict
+ or typing_extensions.get_origin(clean_type) == dict
+ or clean_type == typing.Dict
+ ) and isinstance(object_, typing.Dict):
+ key_type = typing_extensions.get_args(clean_type)[0]
+ value_type = typing_extensions.get_args(clean_type)[1]
+
+ return {
+ key: convert_and_respect_annotation_metadata(
+ object_=value,
+ annotation=annotation,
+ inner_type=value_type,
+ direction=direction,
+ )
+ for key, value in object_.items()
+ }
+
+ # If you're iterating on a string, do not bother to coerce it to a sequence.
+ if not isinstance(object_, str):
+ if (
+ typing_extensions.get_origin(clean_type) == typing.Set
+ or typing_extensions.get_origin(clean_type) == set
+ or clean_type == typing.Set
+ ) and isinstance(object_, typing.Set):
+ inner_type = typing_extensions.get_args(clean_type)[0]
+ return {
+ convert_and_respect_annotation_metadata(
+ object_=item,
+ annotation=annotation,
+ inner_type=inner_type,
+ direction=direction,
+ )
+ for item in object_
+ }
+ elif (
+ (
+ typing_extensions.get_origin(clean_type) == typing.List
+ or typing_extensions.get_origin(clean_type) == list
+ or clean_type == typing.List
+ )
+ and isinstance(object_, typing.List)
+ ) or (
+ (
+ typing_extensions.get_origin(clean_type) == typing.Sequence
+ or typing_extensions.get_origin(clean_type) == collections.abc.Sequence
+ or clean_type == typing.Sequence
+ )
+ and isinstance(object_, typing.Sequence)
+ ):
+ inner_type = typing_extensions.get_args(clean_type)[0]
+ return [
+ convert_and_respect_annotation_metadata(
+ object_=item,
+ annotation=annotation,
+ inner_type=inner_type,
+ direction=direction,
+ )
+ for item in object_
+ ]
+
+ if typing_extensions.get_origin(clean_type) == typing.Union:
+ # We should be able to ~relatively~ safely try to convert keys against all
+ # member types in the union, the edge case here is if one member aliases a field
+ # of the same name to a different name from another member
+ # Or if another member aliases a field of the same name that another member does not.
+ for member in typing_extensions.get_args(clean_type):
+ object_ = convert_and_respect_annotation_metadata(
+ object_=object_,
+ annotation=annotation,
+ inner_type=member,
+ direction=direction,
+ )
+ return object_
+
+ annotated_type = _get_annotation(annotation)
+ if annotated_type is None:
+ return object_
+
+ # If the object is not a TypedDict, a Union, or other container (list, set, sequence, etc.)
+ # Then we can safely call it on the recursive conversion.
+ return object_
+
+
+def _convert_mapping(
+ object_: typing.Mapping[str, object],
+ expected_type: typing.Any,
+ direction: typing.Literal["read", "write"],
+) -> typing.Mapping[str, object]:
+ converted_object: typing.Dict[str, object] = {}
+ try:
+ annotations = typing_extensions.get_type_hints(expected_type, include_extras=True)
+ except NameError:
+ # The TypedDict contains a circular reference, so
+ # we use the __annotations__ attribute directly.
+ annotations = getattr(expected_type, "__annotations__", {})
+ aliases_to_field_names = _get_alias_to_field_name(annotations)
+ for key, value in object_.items():
+ if direction == "read" and key in aliases_to_field_names:
+ dealiased_key = aliases_to_field_names.get(key)
+ if dealiased_key is not None:
+ type_ = annotations.get(dealiased_key)
+ else:
+ type_ = annotations.get(key)
+ # Note you can't get the annotation by the field name if you're in read mode, so you must check the aliases map
+ #
+ # So this is effectively saying if we're in write mode, and we don't have a type, or if we're in read mode and we don't have an alias
+ # then we can just pass the value through as is
+ if type_ is None:
+ converted_object[key] = value
+ elif direction == "read" and key not in aliases_to_field_names:
+ converted_object[key] = convert_and_respect_annotation_metadata(
+ object_=value, annotation=type_, direction=direction
+ )
+ else:
+ converted_object[_alias_key(key, type_, direction, aliases_to_field_names)] = (
+ convert_and_respect_annotation_metadata(object_=value, annotation=type_, direction=direction)
+ )
+ return converted_object
+
+
+def _get_annotation(type_: typing.Any) -> typing.Optional[typing.Any]:
+ maybe_annotated_type = typing_extensions.get_origin(type_)
+ if maybe_annotated_type is None:
+ return None
+
+ if maybe_annotated_type == typing_extensions.NotRequired:
+ type_ = typing_extensions.get_args(type_)[0]
+ maybe_annotated_type = typing_extensions.get_origin(type_)
+
+ if maybe_annotated_type == typing_extensions.Annotated:
+ return type_
+
+ return None
+
+
+def _remove_annotations(type_: typing.Any) -> typing.Any:
+ maybe_annotated_type = typing_extensions.get_origin(type_)
+ if maybe_annotated_type is None:
+ return type_
+
+ if maybe_annotated_type == typing_extensions.NotRequired:
+ return _remove_annotations(typing_extensions.get_args(type_)[0])
+
+ if maybe_annotated_type == typing_extensions.Annotated:
+ return _remove_annotations(typing_extensions.get_args(type_)[0])
+
+ return type_
+
+
+def get_alias_to_field_mapping(type_: typing.Any) -> typing.Dict[str, str]:
+ annotations = typing_extensions.get_type_hints(type_, include_extras=True)
+ return _get_alias_to_field_name(annotations)
+
+
+def get_field_to_alias_mapping(type_: typing.Any) -> typing.Dict[str, str]:
+ annotations = typing_extensions.get_type_hints(type_, include_extras=True)
+ return _get_field_to_alias_name(annotations)
+
+
+def _get_alias_to_field_name(
+ field_to_hint: typing.Dict[str, typing.Any],
+) -> typing.Dict[str, str]:
+ aliases = {}
+ for field, hint in field_to_hint.items():
+ maybe_alias = _get_alias_from_type(hint)
+ if maybe_alias is not None:
+ aliases[maybe_alias] = field
+ return aliases
+
+
+def _get_field_to_alias_name(
+ field_to_hint: typing.Dict[str, typing.Any],
+) -> typing.Dict[str, str]:
+ aliases = {}
+ for field, hint in field_to_hint.items():
+ maybe_alias = _get_alias_from_type(hint)
+ if maybe_alias is not None:
+ aliases[field] = maybe_alias
+ return aliases
+
+
+def _get_alias_from_type(type_: typing.Any) -> typing.Optional[str]:
+ maybe_annotated_type = _get_annotation(type_)
+
+ if maybe_annotated_type is not None:
+ # The actual annotations are 1 onward, the first is the annotated type
+ annotations = typing_extensions.get_args(maybe_annotated_type)[1:]
+
+ for annotation in annotations:
+ if isinstance(annotation, FieldMetadata) and annotation.alias is not None:
+ return annotation.alias
+ return None
+
+
+def _alias_key(
+ key: str,
+ type_: typing.Any,
+ direction: typing.Literal["read", "write"],
+ aliases_to_field_names: typing.Dict[str, str],
+) -> str:
+ if direction == "read":
+ return aliases_to_field_names.get(key, key)
+ return _get_alias_from_type(type_=type_) or key
diff --git a/src/webflow/environment.py b/src/webflow/environment.py
index ed0e03d..07a5c81 100644
--- a/src/webflow/environment.py
+++ b/src/webflow/environment.py
@@ -1,7 +1,19 @@
# 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):
+ self.base = base
+ self.data_api = data_api
+ self.content_delivery_api = content_delivery_api
+
+
+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",
+)
diff --git a/src/webflow/errors/__init__.py b/src/webflow/errors/__init__.py
index 3b6de05..bd5f618 100644
--- a/src/webflow/errors/__init__.py
+++ b/src/webflow/errors/__init__.py
@@ -1,12 +1,49 @@
# This file was auto-generated by Fern from our API Definition.
-from .bad_request_error import BadRequestError
-from .conflict_error import ConflictError
-from .forbidden_error import ForbiddenError
-from .internal_server_error import InternalServerError
-from .not_found_error import NotFoundError
-from .too_many_requests_error import TooManyRequestsError
-from .unauthorized_error import UnauthorizedError
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .bad_request_error import BadRequestError
+ from .conflict_error import ConflictError
+ from .forbidden_error import ForbiddenError
+ from .internal_server_error import InternalServerError
+ from .not_found_error import NotFoundError
+ from .too_many_requests_error import TooManyRequestsError
+ from .unauthorized_error import UnauthorizedError
+_dynamic_imports: typing.Dict[str, str] = {
+ "BadRequestError": ".bad_request_error",
+ "ConflictError": ".conflict_error",
+ "ForbiddenError": ".forbidden_error",
+ "InternalServerError": ".internal_server_error",
+ "NotFoundError": ".not_found_error",
+ "TooManyRequestsError": ".too_many_requests_error",
+ "UnauthorizedError": ".unauthorized_error",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
__all__ = [
"BadRequestError",
diff --git a/src/webflow/errors/bad_request_error.py b/src/webflow/errors/bad_request_error.py
index 44a05f4..ec78e26 100644
--- a/src/webflow/errors/bad_request_error.py
+++ b/src/webflow/errors/bad_request_error.py
@@ -6,5 +6,5 @@
class BadRequestError(ApiError):
- def __init__(self, body: typing.Any):
- super().__init__(status_code=400, body=body)
+ def __init__(self, body: typing.Any, headers: typing.Optional[typing.Dict[str, str]] = None):
+ super().__init__(status_code=400, headers=headers, body=body)
diff --git a/src/webflow/errors/conflict_error.py b/src/webflow/errors/conflict_error.py
index 416399a..be04e01 100644
--- a/src/webflow/errors/conflict_error.py
+++ b/src/webflow/errors/conflict_error.py
@@ -6,5 +6,5 @@
class ConflictError(ApiError):
- def __init__(self, body: typing.Any):
- super().__init__(status_code=409, body=body)
+ def __init__(self, body: typing.Any, headers: typing.Optional[typing.Dict[str, str]] = None):
+ super().__init__(status_code=409, headers=headers, body=body)
diff --git a/src/webflow/errors/forbidden_error.py b/src/webflow/errors/forbidden_error.py
index 3f237b5..07d7e45 100644
--- a/src/webflow/errors/forbidden_error.py
+++ b/src/webflow/errors/forbidden_error.py
@@ -6,5 +6,5 @@
class ForbiddenError(ApiError):
- def __init__(self, body: typing.Any):
- super().__init__(status_code=403, body=body)
+ def __init__(self, body: typing.Any, headers: typing.Optional[typing.Dict[str, str]] = None):
+ super().__init__(status_code=403, headers=headers, body=body)
diff --git a/src/webflow/errors/internal_server_error.py b/src/webflow/errors/internal_server_error.py
index c2764d6..2c41ca5 100644
--- a/src/webflow/errors/internal_server_error.py
+++ b/src/webflow/errors/internal_server_error.py
@@ -3,8 +3,9 @@
import typing
from ..core.api_error import ApiError
+from ..types.error import Error
class InternalServerError(ApiError):
- def __init__(self, body: typing.Any):
- super().__init__(status_code=500, body=body)
+ def __init__(self, body: Error, headers: typing.Optional[typing.Dict[str, str]] = None):
+ super().__init__(status_code=500, headers=headers, body=body)
diff --git a/src/webflow/errors/not_found_error.py b/src/webflow/errors/not_found_error.py
index 4405a19..e7ed720 100644
--- a/src/webflow/errors/not_found_error.py
+++ b/src/webflow/errors/not_found_error.py
@@ -3,8 +3,9 @@
import typing
from ..core.api_error import ApiError
+from ..types.error import Error
class NotFoundError(ApiError):
- def __init__(self, body: typing.Any):
- super().__init__(status_code=404, body=body)
+ def __init__(self, body: Error, headers: typing.Optional[typing.Dict[str, str]] = None):
+ super().__init__(status_code=404, headers=headers, body=body)
diff --git a/src/webflow/errors/too_many_requests_error.py b/src/webflow/errors/too_many_requests_error.py
index 3bbbb0d..a0743ee 100644
--- a/src/webflow/errors/too_many_requests_error.py
+++ b/src/webflow/errors/too_many_requests_error.py
@@ -3,8 +3,9 @@
import typing
from ..core.api_error import ApiError
+from ..types.error import Error
class TooManyRequestsError(ApiError):
- def __init__(self, body: typing.Any):
- super().__init__(status_code=429, body=body)
+ def __init__(self, body: Error, headers: typing.Optional[typing.Dict[str, str]] = None):
+ super().__init__(status_code=429, headers=headers, body=body)
diff --git a/src/webflow/errors/unauthorized_error.py b/src/webflow/errors/unauthorized_error.py
index e5c83f6..2345489 100644
--- a/src/webflow/errors/unauthorized_error.py
+++ b/src/webflow/errors/unauthorized_error.py
@@ -3,8 +3,9 @@
import typing
from ..core.api_error import ApiError
+from ..types.error import Error
class UnauthorizedError(ApiError):
- def __init__(self, body: typing.Any):
- super().__init__(status_code=401, body=body)
+ def __init__(self, body: Error, headers: typing.Optional[typing.Dict[str, str]] = None):
+ super().__init__(status_code=401, headers=headers, body=body)
diff --git a/src/webflow/oauth.py b/src/webflow/oauth.py
index ce06031..70b35fe 100644
--- a/src/webflow/oauth.py
+++ b/src/webflow/oauth.py
@@ -7,7 +7,7 @@
from .core.api_error import ApiError
from .core.jsonable_encoder import jsonable_encoder
from .environment import WebflowEnvironment
-from .types import OauthScope
+from .types.oauth_scope import OauthScope
try:
import pydantic.v1 as pydantic # type: ignore
diff --git a/src/webflow/resources/__init__.py b/src/webflow/resources/__init__.py
index b2501ad..7eea249 100644
--- a/src/webflow/resources/__init__.py
+++ b/src/webflow/resources/__init__.py
@@ -1,63 +1,118 @@
# This file was auto-generated by Fern from our API Definition.
-from . import (
- access_groups,
- assets,
- collections,
- ecommerce,
- forms,
- inventory,
- orders,
- pages,
- products,
- scripts,
- sites,
- token,
- users,
- webhooks,
-)
-from .access_groups import AccessGroupsListRequestSort
-from .inventory import InventoryUpdateRequestInventoryType
-from .orders import OrdersRefundRequestReason
-from .pages import DomWriteNodesItem
-from .products import (
- ProductSkuCreateProduct,
- ProductSkuCreateProductFieldData,
- ProductSkuCreateProductFieldDataEcProductType,
- ProductSkuCreateProductFieldDataTaxCategory,
- ProductSkuCreateSku,
- ProductSkuCreateSkuFieldData,
- ProductSkuCreateSkuFieldDataCompareAtPrice,
- ProductSkuCreateSkuFieldDataEcSkuBillingMethod,
- ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlan,
- ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlanInterval,
- ProductSkuCreateSkuFieldDataPrice,
- ProductsCreateSkuResponse,
-)
-from .users import UsersListRequestSort, UsersUpdateRequestData
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from . import (
+ assets,
+ collections,
+ components,
+ ecommerce,
+ forms,
+ inventory,
+ orders,
+ pages,
+ products,
+ scripts,
+ sites,
+ token,
+ webhooks,
+ workspaces,
+ )
+ from .components import (
+ ComponentDomWriteNodesItem,
+ ComponentPropertiesWritePropertiesItem,
+ ComponentsUpdateContentResponse,
+ ComponentsUpdatePropertiesResponse,
+ )
+ from .inventory import EcommInventoryChangedPayload, InventoryUpdateRequestInventoryType
+ from .orders import OrdersListRequestStatus, OrdersRefundRequestReason
+ from .pages import (
+ PageDomWriteNodesItem,
+ PageMetadataWriteOpenGraph,
+ PageMetadataWriteSeo,
+ UpdateStaticContentResponse,
+ )
+ from .products import ProductSkuCreateProduct, ProductSkuCreateSku, ProductsCreateSkuResponse
+ from .sites import SitesPublishResponse
+_dynamic_imports: typing.Dict[str, str] = {
+ "ComponentDomWriteNodesItem": ".components",
+ "ComponentPropertiesWritePropertiesItem": ".components",
+ "ComponentsUpdateContentResponse": ".components",
+ "ComponentsUpdatePropertiesResponse": ".components",
+ "EcommInventoryChangedPayload": ".inventory",
+ "InventoryUpdateRequestInventoryType": ".inventory",
+ "OrdersListRequestStatus": ".orders",
+ "OrdersRefundRequestReason": ".orders",
+ "PageDomWriteNodesItem": ".pages",
+ "PageMetadataWriteOpenGraph": ".pages",
+ "PageMetadataWriteSeo": ".pages",
+ "ProductSkuCreateProduct": ".products",
+ "ProductSkuCreateSku": ".products",
+ "ProductsCreateSkuResponse": ".products",
+ "SitesPublishResponse": ".sites",
+ "UpdateStaticContentResponse": ".pages",
+ "assets": ".assets",
+ "collections": ".collections",
+ "components": ".components",
+ "ecommerce": ".ecommerce",
+ "forms": ".forms",
+ "inventory": ".inventory",
+ "orders": ".orders",
+ "pages": ".pages",
+ "products": ".products",
+ "scripts": ".scripts",
+ "sites": ".sites",
+ "token": ".token",
+ "webhooks": ".webhooks",
+ "workspaces": ".workspaces",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
__all__ = [
- "AccessGroupsListRequestSort",
- "DomWriteNodesItem",
+ "ComponentDomWriteNodesItem",
+ "ComponentPropertiesWritePropertiesItem",
+ "ComponentsUpdateContentResponse",
+ "ComponentsUpdatePropertiesResponse",
+ "EcommInventoryChangedPayload",
"InventoryUpdateRequestInventoryType",
+ "OrdersListRequestStatus",
"OrdersRefundRequestReason",
+ "PageDomWriteNodesItem",
+ "PageMetadataWriteOpenGraph",
+ "PageMetadataWriteSeo",
"ProductSkuCreateProduct",
- "ProductSkuCreateProductFieldData",
- "ProductSkuCreateProductFieldDataEcProductType",
- "ProductSkuCreateProductFieldDataTaxCategory",
"ProductSkuCreateSku",
- "ProductSkuCreateSkuFieldData",
- "ProductSkuCreateSkuFieldDataCompareAtPrice",
- "ProductSkuCreateSkuFieldDataEcSkuBillingMethod",
- "ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlan",
- "ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlanInterval",
- "ProductSkuCreateSkuFieldDataPrice",
"ProductsCreateSkuResponse",
- "UsersListRequestSort",
- "UsersUpdateRequestData",
- "access_groups",
+ "SitesPublishResponse",
+ "UpdateStaticContentResponse",
"assets",
"collections",
+ "components",
"ecommerce",
"forms",
"inventory",
@@ -67,6 +122,6 @@
"scripts",
"sites",
"token",
- "users",
"webhooks",
+ "workspaces",
]
diff --git a/src/webflow/resources/access_groups/__init__.py b/src/webflow/resources/access_groups/__init__.py
deleted file mode 100644
index b46e2ae..0000000
--- a/src/webflow/resources/access_groups/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .types import AccessGroupsListRequestSort
-
-__all__ = ["AccessGroupsListRequestSort"]
diff --git a/src/webflow/resources/access_groups/client.py b/src/webflow/resources/access_groups/client.py
deleted file mode 100644
index bfd306e..0000000
--- a/src/webflow/resources/access_groups/client.py
+++ /dev/null
@@ -1,200 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-import urllib.parse
-from json.decoder import JSONDecodeError
-
-from ...core.api_error import ApiError
-from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from ...core.jsonable_encoder import jsonable_encoder
-from ...core.remove_none_from_dict import remove_none_from_dict
-from ...core.request_options import RequestOptions
-from ...errors.bad_request_error import BadRequestError
-from ...errors.forbidden_error import ForbiddenError
-from ...errors.internal_server_error import InternalServerError
-from ...errors.not_found_error import NotFoundError
-from ...errors.too_many_requests_error import TooManyRequestsError
-from ...errors.unauthorized_error import UnauthorizedError
-from ...types.access_group_list import AccessGroupList
-from .types.access_groups_list_request_sort import AccessGroupsListRequestSort
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class AccessGroupsClient:
- def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
-
- def list(
- self,
- site_id: str,
- *,
- offset: typing.Optional[float] = None,
- limit: typing.Optional[float] = None,
- sort: typing.Optional[AccessGroupsListRequestSort] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AccessGroupList:
- """
- Get a list of access groups for a site Required scope | `users:read`
-
- 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)
-
- - sort: typing.Optional[AccessGroupsListRequestSort]. Sort string to use when ordering access groups
- Can be prefixed with a `-` to reverse the sort (ex. `-CreatedOn`)
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
-
- client = Webflow(
- access_token="YOUR_ACCESS_TOKEN",
- )
- client.access_groups.list(
- site_id="site_id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/accessgroups"
- ),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "offset": offset,
- "limit": limit,
- "sort": sort,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(AccessGroupList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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 AsyncAccessGroupsClient:
- def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
-
- async def list(
- self,
- site_id: str,
- *,
- offset: typing.Optional[float] = None,
- limit: typing.Optional[float] = None,
- sort: typing.Optional[AccessGroupsListRequestSort] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AccessGroupList:
- """
- Get a list of access groups for a site Required scope | `users:read`
-
- 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)
-
- - sort: typing.Optional[AccessGroupsListRequestSort]. Sort string to use when ordering access groups
- Can be prefixed with a `-` to reverse the sort (ex. `-CreatedOn`)
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
-
- client = AsyncWebflow(
- access_token="YOUR_ACCESS_TOKEN",
- )
- await client.access_groups.list(
- site_id="site_id",
- )
- """
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/accessgroups"
- ),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "offset": offset,
- "limit": limit,
- "sort": sort,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(AccessGroupList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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/access_groups/types/__init__.py b/src/webflow/resources/access_groups/types/__init__.py
deleted file mode 100644
index e721e22..0000000
--- a/src/webflow/resources/access_groups/types/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .access_groups_list_request_sort import AccessGroupsListRequestSort
-
-__all__ = ["AccessGroupsListRequestSort"]
diff --git a/src/webflow/resources/access_groups/types/access_groups_list_request_sort.py b/src/webflow/resources/access_groups/types/access_groups_list_request_sort.py
deleted file mode 100644
index 1a5d034..0000000
--- a/src/webflow/resources/access_groups/types/access_groups_list_request_sort.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import enum
-import typing
-
-T_Result = typing.TypeVar("T_Result")
-
-
-class AccessGroupsListRequestSort(str, enum.Enum):
- CREATED_ON_ASCENDING = "CreatedOn"
- """
- Sorts users in ascending order based on their created date
- """
-
- CREATED_ON_DESCENDING = "-CreatedOn"
- """
- Sorts users in descending order based on their created date
- """
-
- def visit(
- self, created_on_ascending: typing.Callable[[], T_Result], created_on_descending: typing.Callable[[], T_Result]
- ) -> T_Result:
- if self is AccessGroupsListRequestSort.CREATED_ON_ASCENDING:
- return created_on_ascending()
- if self is AccessGroupsListRequestSort.CREATED_ON_DESCENDING:
- return created_on_descending()
diff --git a/src/webflow/resources/assets/__init__.py b/src/webflow/resources/assets/__init__.py
index f3ea265..5cde020 100644
--- a/src/webflow/resources/assets/__init__.py
+++ b/src/webflow/resources/assets/__init__.py
@@ -1,2 +1,4 @@
# This file was auto-generated by Fern from our API Definition.
+# isort: skip_file
+
diff --git a/src/webflow/resources/assets/client.py b/src/webflow/resources/assets/client.py
index 7be5754..ae22ab4 100644
--- a/src/webflow/resources/assets/client.py
+++ b/src/webflow/resources/assets/client.py
@@ -1,29 +1,15 @@
# This file was auto-generated by Fern from our API Definition.
import typing
-import urllib.parse
-from json.decoder import JSONDecodeError
-from ...core.api_error import ApiError
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from ...core.jsonable_encoder import jsonable_encoder
-from ...core.remove_none_from_dict import remove_none_from_dict
from ...core.request_options import RequestOptions
-from ...errors.bad_request_error import BadRequestError
-from ...errors.internal_server_error import InternalServerError
-from ...errors.not_found_error import NotFoundError
-from ...errors.too_many_requests_error import TooManyRequestsError
-from ...errors.unauthorized_error import UnauthorizedError
from ...types.asset import Asset
from ...types.asset_folder import AssetFolder
from ...types.asset_folder_list import AssetFolderList
from ...types.asset_upload import AssetUpload
from ...types.assets import Assets
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+from .raw_client import AsyncRawAssetsClient, RawAssetsClient
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
@@ -31,63 +17,66 @@
class AssetsClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = RawAssetsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawAssetsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawAssetsClient
+ """
+ return self._raw_client
- def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Assets:
+ def list(
+ self,
+ site_id: str,
+ *,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> Assets:
"""
- List assets for a given site Required scope | `assets:read`
+ List of assets uploaded to a site
+
+ Required scope | `assets:read`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Assets
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.assets.list(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
+ offset=1,
+ limit=1,
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/assets"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Assets, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.list(site_id, offset=offset, limit=limit, request_options=request_options)
+ return _response.data
def create(
self,
@@ -99,306 +88,208 @@ def create(
request_options: typing.Optional[RequestOptions] = None,
) -> AssetUpload:
"""
- Create a new asset entry. 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`
+ The first step in uploading an asset to a site.
+
+
+ This endpoint generates a response with the following information: `uploadUrl` and `uploadDetails`.
+
+
+ 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.
- Parameters:
- - site_id: str. Unique identifier for a Site
- - file_name: str. file name including file extension
+ To learn more about how to upload assets to Webflow, see our [assets guide](/data/docs/working-with-assets).
- - file_hash: str. MD5 hash of the file
+ Required scope | `assets:write`
- - parent_folder: typing.Optional[str]. id of the Asset folder (optional)
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ file_name : str
+ File name including file extension. File names must be less than 100 characters.
+
+ file_hash : str
+ MD5 hash of the file
+
+ parent_folder : typing.Optional[str]
+ ID of the Asset folder (optional)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AssetUpload
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.assets.create(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
file_name="file.png",
file_hash="3c7d87c9575702bc3b1e991f4d3c638e",
- parent_folder="6436b1ce5281cace05b65aea",
)
"""
- _request: typing.Dict[str, typing.Any] = {"fileName": file_name, "fileHash": file_hash}
- if parent_folder is not OMIT:
- _request["parentFolder"] = parent_folder
- _response = self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/assets"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.create(
+ site_id,
+ file_name=file_name,
+ file_hash=file_hash,
+ parent_folder=parent_folder,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(AssetUpload, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
def get(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Asset:
"""
- Get an Asset Required scope | `assets:read`
+ Get details about an asset
- Parameters:
- - asset_id: str. Unique identifier for an Asset on a site
+ Required scope | `assets:read`
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Parameters
+ ----------
+ asset_id : str
+ Unique identifier for an Asset on a site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Asset
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.assets.get(
- asset_id="asset_id",
+ asset_id="580e63fc8c9a982ac9b8b745",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"assets/{jsonable_encoder(asset_id)}"),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Asset, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.get(asset_id, request_options=request_options)
+ return _response.data
def delete(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
"""
Delete an Asset
- Parameters:
- - asset_id: str. Unique identifier for an Asset on a site
+ Required Scope: `assets: write`
+
+ Parameters
+ ----------
+ asset_id : str
+ Unique identifier for an Asset on a site
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.assets.delete(
- asset_id="asset_id",
+ asset_id="580e63fc8c9a982ac9b8b745",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "DELETE",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"assets/{jsonable_encoder(asset_id)}"),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.delete(asset_id, request_options=request_options)
+ return _response.data
def update(
- self, asset_id: str, *, display_name: str, request_options: typing.Optional[RequestOptions] = None
+ self,
+ asset_id: str,
+ *,
+ locale_id: typing.Optional[str] = OMIT,
+ display_name: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
) -> Asset:
"""
- Update an Asset Required scope | `assets:write`
+ Update details of an Asset.
+
+ Required scope | `assets:write`
+
+ Parameters
+ ----------
+ asset_id : str
+ Unique identifier for an Asset on a site
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific locale. Applicable, when using localization.
- Parameters:
- - asset_id: str. Unique identifier for an Asset on a site
+ display_name : typing.Optional[str]
+ A human readable name for the asset
- - display_name: str. file name including file extension
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Returns
+ -------
+ Asset
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.assets.update(
- asset_id="asset_id",
- display_name="bulldoze.png",
+ asset_id="580e63fc8c9a982ac9b8b745",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "PATCH",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"assets/{jsonable_encoder(asset_id)}"),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder({"displayName": display_name})
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder({"displayName": display_name}),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.update(
+ asset_id, locale_id=locale_id, display_name=display_name, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Asset, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
def list_folders(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> AssetFolderList:
"""
- List Asset Folders within a given site Required scope | `assets:read`
+ List Asset Folders within a given site
+
+ Required scope | `assets:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- Parameters:
- - site_id: str. Unique identifier for a Site
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Returns
+ -------
+ AssetFolderList
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.assets.list_folders(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/asset_folders"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(AssetFolderList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.list_folders(site_id, request_options=request_options)
+ return _response.data
def create_folder(
self,
@@ -409,193 +300,152 @@ def create_folder(
request_options: typing.Optional[RequestOptions] = None,
) -> AssetFolder:
"""
- Create an Asset Folder within a given site Required scope | `assets:write`
+ Create an Asset Folder within a given site
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Required scope | `assets:write`
- - display_name: str. A human readable name for the Asset Folder
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- - parent_folder: typing.Optional[str]. An (optional) pointer to a parent Asset Folder (or null for root)
+ display_name : str
+ A human readable name for the Asset Folder
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ parent_folder : typing.Optional[str]
+ An (optional) pointer to a parent Asset Folder (or null for root)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AssetFolder
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.assets.create_folder(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
display_name="my asset folder",
- parent_folder="6390c49774a71f99f21a08eb",
)
"""
- _request: typing.Dict[str, typing.Any] = {"displayName": display_name}
- if parent_folder is not OMIT:
- _request["parentFolder"] = parent_folder
- _response = self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/asset_folders"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.create_folder(
+ site_id, display_name=display_name, parent_folder=parent_folder, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(AssetFolder, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
def get_folder(
self, asset_folder_id: str, *, request_options: typing.Optional[RequestOptions] = None
) -> AssetFolder:
"""
- Get details about a specific Asset Folder Required scope | `assets:read`
+ Get details about a specific Asset Folder
+
+ Required scope | `assets:read`
+
+ Parameters
+ ----------
+ asset_folder_id : str
+ Unique identifier for an Asset Folder
- Parameters:
- - asset_folder_id: str. Unique identifier for an Asset Folder
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Returns
+ -------
+ AssetFolder
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.assets.get_folder(
- asset_folder_id="asset_folder_id",
+ asset_folder_id="6390c49774a71f0e3c1a08ee",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"asset_folders/{jsonable_encoder(asset_folder_id)}"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(AssetFolder, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.get_folder(asset_folder_id, request_options=request_options)
+ return _response.data
class AsyncAssetsClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = AsyncRawAssetsClient(client_wrapper=client_wrapper)
- async def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Assets:
+ @property
+ def with_raw_response(self) -> AsyncRawAssetsClient:
"""
- List assets for a given site Required scope | `assets:read`
+ Retrieves a raw implementation of this client that returns raw responses.
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Returns
+ -------
+ AsyncRawAssetsClient
+ """
+ return self._raw_client
+
+ async def list(
+ self,
+ site_id: str,
+ *,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> Assets:
+ """
+ List of assets uploaded to a site
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Required scope | `assets:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Assets
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.assets.list(
- site_id="site_id",
- )
+
+
+ async def main() -> None:
+ await client.assets.list(
+ site_id="580e63e98c9a982ac9b8b741",
+ offset=1,
+ limit=1,
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/assets"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Assets, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.list(site_id, offset=offset, limit=limit, request_options=request_options)
+ return _response.data
async def create(
self,
@@ -607,308 +457,250 @@ async def create(
request_options: typing.Optional[RequestOptions] = None,
) -> AssetUpload:
"""
- Create a new asset entry. 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`
+ The first step in uploading an asset to a site.
+
+
+ This endpoint generates a response with the following information: `uploadUrl` and `uploadDetails`.
+
+
+ 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.
+
- Parameters:
- - site_id: str. Unique identifier for a Site
+ To learn more about how to upload assets to Webflow, see our [assets guide](/data/docs/working-with-assets).
- - file_name: str. file name including file extension
+ Required scope | `assets:write`
- - file_hash: str. MD5 hash of the file
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- - parent_folder: typing.Optional[str]. id of the Asset folder (optional)
+ file_name : str
+ File name including file extension. File names must be less than 100 characters.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ file_hash : str
+ MD5 hash of the file
+
+ parent_folder : typing.Optional[str]
+ ID of the Asset folder (optional)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AssetUpload
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.assets.create(
- site_id="site_id",
- file_name="file.png",
- file_hash="3c7d87c9575702bc3b1e991f4d3c638e",
- parent_folder="6436b1ce5281cace05b65aea",
- )
+
+
+ async def main() -> None:
+ await client.assets.create(
+ site_id="580e63e98c9a982ac9b8b741",
+ file_name="file.png",
+ file_hash="3c7d87c9575702bc3b1e991f4d3c638e",
+ )
+
+
+ asyncio.run(main())
"""
- _request: typing.Dict[str, typing.Any] = {"fileName": file_name, "fileHash": file_hash}
- if parent_folder is not OMIT:
- _request["parentFolder"] = parent_folder
- _response = await self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/assets"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.create(
+ site_id,
+ file_name=file_name,
+ file_hash=file_hash,
+ parent_folder=parent_folder,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(AssetUpload, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
async def get(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Asset:
"""
- Get an Asset Required scope | `assets:read`
+ Get details about an asset
+
+ Required scope | `assets:read`
+
+ Parameters
+ ----------
+ asset_id : str
+ Unique identifier for an Asset on a site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- Parameters:
- - asset_id: str. Unique identifier for an Asset on a site
+ Returns
+ -------
+ Asset
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.assets.get(
- asset_id="asset_id",
- )
+
+
+ async def main() -> None:
+ await client.assets.get(
+ asset_id="580e63fc8c9a982ac9b8b745",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"assets/{jsonable_encoder(asset_id)}"),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Asset, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.get(asset_id, request_options=request_options)
+ return _response.data
async def delete(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
"""
Delete an Asset
- Parameters:
- - asset_id: str. Unique identifier for an Asset on a site
+ Required Scope: `assets: write`
+
+ Parameters
+ ----------
+ asset_id : str
+ Unique identifier for an Asset on a site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.assets.delete(
- asset_id="asset_id",
- )
+
+
+ async def main() -> None:
+ await client.assets.delete(
+ asset_id="580e63fc8c9a982ac9b8b745",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "DELETE",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"assets/{jsonable_encoder(asset_id)}"),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.delete(asset_id, request_options=request_options)
+ return _response.data
async def update(
- self, asset_id: str, *, display_name: str, request_options: typing.Optional[RequestOptions] = None
+ self,
+ asset_id: str,
+ *,
+ locale_id: typing.Optional[str] = OMIT,
+ display_name: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
) -> Asset:
"""
- Update an Asset Required scope | `assets:write`
+ Update details of an Asset.
+
+ Required scope | `assets:write`
+
+ Parameters
+ ----------
+ asset_id : str
+ Unique identifier for an Asset on a site
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific locale. Applicable, when using localization.
- Parameters:
- - asset_id: str. Unique identifier for an Asset on a site
+ display_name : typing.Optional[str]
+ A human readable name for the asset
- - display_name: str. file name including file extension
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Returns
+ -------
+ Asset
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.assets.update(
- asset_id="asset_id",
- display_name="bulldoze.png",
- )
+
+
+ async def main() -> None:
+ await client.assets.update(
+ asset_id="580e63fc8c9a982ac9b8b745",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "PATCH",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"assets/{jsonable_encoder(asset_id)}"),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder({"displayName": display_name})
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder({"displayName": display_name}),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.update(
+ asset_id, locale_id=locale_id, display_name=display_name, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Asset, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
async def list_folders(
self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
) -> AssetFolderList:
"""
- List Asset Folders within a given site Required scope | `assets:read`
+ List Asset Folders within a given site
+
+ Required scope | `assets:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Returns
+ -------
+ AssetFolderList
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.assets.list_folders(
- site_id="site_id",
- )
+
+
+ async def main() -> None:
+ await client.assets.list_folders(
+ site_id="580e63e98c9a982ac9b8b741",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/asset_folders"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(AssetFolderList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.list_folders(site_id, request_options=request_options)
+ return _response.data
async def create_folder(
self,
@@ -919,129 +711,93 @@ async def create_folder(
request_options: typing.Optional[RequestOptions] = None,
) -> AssetFolder:
"""
- Create an Asset Folder within a given site Required scope | `assets:write`
+ Create an Asset Folder within a given site
+
+ Required scope | `assets:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- Parameters:
- - site_id: str. Unique identifier for a Site
+ display_name : str
+ A human readable name for the Asset Folder
- - display_name: str. A human readable name for the Asset Folder
+ parent_folder : typing.Optional[str]
+ An (optional) pointer to a parent Asset Folder (or null for root)
- - parent_folder: typing.Optional[str]. An (optional) pointer to a parent Asset Folder (or null for root)
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Returns
+ -------
+ AssetFolder
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.assets.create_folder(
- site_id="site_id",
- display_name="my asset folder",
- parent_folder="6390c49774a71f99f21a08eb",
- )
+
+
+ async def main() -> None:
+ await client.assets.create_folder(
+ site_id="580e63e98c9a982ac9b8b741",
+ display_name="my asset folder",
+ )
+
+
+ asyncio.run(main())
"""
- _request: typing.Dict[str, typing.Any] = {"displayName": display_name}
- if parent_folder is not OMIT:
- _request["parentFolder"] = parent_folder
- _response = await self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/asset_folders"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.create_folder(
+ site_id, display_name=display_name, parent_folder=parent_folder, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(AssetFolder, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
async def get_folder(
self, asset_folder_id: str, *, request_options: typing.Optional[RequestOptions] = None
) -> AssetFolder:
"""
- Get details about a specific Asset Folder Required scope | `assets:read`
+ Get details about a specific Asset Folder
+
+ Required scope | `assets:read`
- Parameters:
- - asset_folder_id: str. Unique identifier for an Asset Folder
+ Parameters
+ ----------
+ asset_folder_id : str
+ Unique identifier for an Asset Folder
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AssetFolder
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.assets.get_folder(
- asset_folder_id="asset_folder_id",
- )
+
+
+ async def main() -> None:
+ await client.assets.get_folder(
+ asset_folder_id="6390c49774a71f0e3c1a08ee",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"asset_folders/{jsonable_encoder(asset_folder_id)}"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(AssetFolder, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.get_folder(asset_folder_id, request_options=request_options)
+ return _response.data
diff --git a/src/webflow/resources/assets/raw_client.py b/src/webflow/resources/assets/raw_client.py
new file mode 100644
index 0000000..5c99d98
--- /dev/null
+++ b/src/webflow/resources/assets/raw_client.py
@@ -0,0 +1,1805 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from ...core.api_error import ApiError
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.http_response import AsyncHttpResponse, HttpResponse
+from ...core.jsonable_encoder import jsonable_encoder
+from ...core.parse_error import ParsingError
+from ...core.pydantic_utilities import parse_obj_as
+from ...core.request_options import RequestOptions
+from ...errors.bad_request_error import BadRequestError
+from ...errors.internal_server_error import InternalServerError
+from ...errors.not_found_error import NotFoundError
+from ...errors.too_many_requests_error import TooManyRequestsError
+from ...errors.unauthorized_error import UnauthorizedError
+from ...types.asset import Asset
+from ...types.asset_folder import AssetFolder
+from ...types.asset_folder_list import AssetFolderList
+from ...types.asset_upload import AssetUpload
+from ...types.assets import Assets
+from ...types.error import Error
+from pydantic import ValidationError
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RawAssetsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def list(
+ self,
+ site_id: str,
+ *,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[Assets]:
+ """
+ List of assets uploaded to a site
+
+ Required scope | `assets:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Assets]
+ Request was successful
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"sites/{jsonable_encoder(site_id)}/assets",
+ base_url=self._client_wrapper.get_environment().base,
+ method="GET",
+ params={
+ "offset": offset,
+ "limit": limit,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Assets,
+ parse_obj_as(
+ type_=Assets, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def create(
+ self,
+ site_id: str,
+ *,
+ file_name: str,
+ file_hash: str,
+ parent_folder: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[AssetUpload]:
+ """
+ The first step in uploading an asset to a site.
+
+
+ This endpoint generates a response with the following information: `uploadUrl` and `uploadDetails`.
+
+
+ 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
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ file_name : str
+ File name including file extension. File names must be less than 100 characters.
+
+ file_hash : str
+ MD5 hash of the file
+
+ parent_folder : typing.Optional[str]
+ ID of the Asset folder (optional)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[AssetUpload]
+ Request was successful
+ """
+ _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,
+ "fileHash": file_hash,
+ "parentFolder": parent_folder,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ AssetUpload,
+ parse_obj_as(
+ type_=AssetUpload, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def get(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[Asset]:
+ """
+ Get details about an asset
+
+ Required scope | `assets:read`
+
+ Parameters
+ ----------
+ asset_id : str
+ Unique identifier for an Asset on a site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Asset]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Asset,
+ parse_obj_as(
+ type_=Asset, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def delete(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[None]:
+ """
+ Delete an Asset
+
+ Required Scope: `assets: write`
+
+ Parameters
+ ----------
+ asset_id : str
+ Unique identifier for an Asset on a site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[None]
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return HttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def update(
+ self,
+ asset_id: str,
+ *,
+ locale_id: typing.Optional[str] = OMIT,
+ display_name: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[Asset]:
+ """
+ Update details of an Asset.
+
+ Required scope | `assets:write`
+
+ Parameters
+ ----------
+ asset_id : str
+ Unique identifier for an Asset on a site
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific locale. Applicable, when using localization.
+
+ display_name : typing.Optional[str]
+ A human readable name for the asset
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Asset]
+ Request was successful
+ """
+ _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,
+ "displayName": display_name,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Asset,
+ parse_obj_as(
+ type_=Asset, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def list_folders(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[AssetFolderList]:
+ """
+ List Asset Folders within a given site
+
+ Required scope | `assets:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[AssetFolderList]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ AssetFolderList,
+ parse_obj_as(
+ type_=AssetFolderList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def create_folder(
+ self,
+ site_id: str,
+ *,
+ display_name: str,
+ parent_folder: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[AssetFolder]:
+ """
+ Create an Asset Folder within a given site
+
+ Required scope | `assets:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ display_name : str
+ A human readable name for the Asset Folder
+
+ parent_folder : typing.Optional[str]
+ An (optional) pointer to a parent Asset Folder (or null for root)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[AssetFolder]
+ Request was successful
+ """
+ _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,
+ "parentFolder": parent_folder,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ AssetFolder,
+ parse_obj_as(
+ type_=AssetFolder, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def get_folder(
+ self, asset_folder_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[AssetFolder]:
+ """
+ Get details about a specific Asset Folder
+
+ Required scope | `assets:read`
+
+ Parameters
+ ----------
+ asset_folder_id : str
+ Unique identifier for an Asset Folder
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[AssetFolder]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ AssetFolder,
+ parse_obj_as(
+ type_=AssetFolder, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawAssetsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def list(
+ self,
+ site_id: str,
+ *,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[Assets]:
+ """
+ List of assets uploaded to a site
+
+ Required scope | `assets:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Assets]
+ Request was successful
+ """
+ _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",
+ params={
+ "offset": offset,
+ "limit": limit,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Assets,
+ parse_obj_as(
+ type_=Assets, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def create(
+ self,
+ site_id: str,
+ *,
+ file_name: str,
+ file_hash: str,
+ parent_folder: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[AssetUpload]:
+ """
+ The first step in uploading an asset to a site.
+
+
+ This endpoint generates a response with the following information: `uploadUrl` and `uploadDetails`.
+
+
+ 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
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ file_name : str
+ File name including file extension. File names must be less than 100 characters.
+
+ file_hash : str
+ MD5 hash of the file
+
+ parent_folder : typing.Optional[str]
+ ID of the Asset folder (optional)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[AssetUpload]
+ Request was successful
+ """
+ _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,
+ "fileHash": file_hash,
+ "parentFolder": parent_folder,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ AssetUpload,
+ parse_obj_as(
+ type_=AssetUpload, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def get(
+ self, asset_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[Asset]:
+ """
+ Get details about an asset
+
+ Required scope | `assets:read`
+
+ Parameters
+ ----------
+ asset_id : str
+ Unique identifier for an Asset on a site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Asset]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Asset,
+ parse_obj_as(
+ type_=Asset, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def delete(
+ self, asset_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[None]:
+ """
+ Delete an Asset
+
+ Required Scope: `assets: write`
+
+ Parameters
+ ----------
+ asset_id : str
+ Unique identifier for an Asset on a site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return AsyncHttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def update(
+ self,
+ asset_id: str,
+ *,
+ locale_id: typing.Optional[str] = OMIT,
+ display_name: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[Asset]:
+ """
+ Update details of an Asset.
+
+ Required scope | `assets:write`
+
+ Parameters
+ ----------
+ asset_id : str
+ Unique identifier for an Asset on a site
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific locale. Applicable, when using localization.
+
+ display_name : typing.Optional[str]
+ A human readable name for the asset
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Asset]
+ Request was successful
+ """
+ _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,
+ "displayName": display_name,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Asset,
+ parse_obj_as(
+ type_=Asset, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def list_folders(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[AssetFolderList]:
+ """
+ List Asset Folders within a given site
+
+ Required scope | `assets:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[AssetFolderList]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ AssetFolderList,
+ parse_obj_as(
+ type_=AssetFolderList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def create_folder(
+ self,
+ site_id: str,
+ *,
+ display_name: str,
+ parent_folder: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[AssetFolder]:
+ """
+ Create an Asset Folder within a given site
+
+ Required scope | `assets:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ display_name : str
+ A human readable name for the Asset Folder
+
+ parent_folder : typing.Optional[str]
+ An (optional) pointer to a parent Asset Folder (or null for root)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[AssetFolder]
+ Request was successful
+ """
+ _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,
+ "parentFolder": parent_folder,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ AssetFolder,
+ parse_obj_as(
+ type_=AssetFolder, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def get_folder(
+ self, asset_folder_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[AssetFolder]:
+ """
+ Get details about a specific Asset Folder
+
+ Required scope | `assets:read`
+
+ Parameters
+ ----------
+ asset_folder_id : str
+ Unique identifier for an Asset Folder
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[AssetFolder]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ AssetFolder,
+ parse_obj_as(
+ type_=AssetFolder, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/collections/__init__.py b/src/webflow/resources/collections/__init__.py
index ea60c9c..07eb5d1 100644
--- a/src/webflow/resources/collections/__init__.py
+++ b/src/webflow/resources/collections/__init__.py
@@ -1,5 +1,100 @@
# This file was auto-generated by Fern from our API Definition.
-from .resources import BulkCollectionItemFieldData, FieldCreateType, ItemsPublishItemResponse, fields, items
+# isort: skip_file
-__all__ = ["BulkCollectionItemFieldData", "FieldCreateType", "ItemsPublishItemResponse", "fields", "items"]
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .resources import (
+ CreateBulkCollectionItemRequestBodyFieldData,
+ CreateBulkCollectionItemRequestBodyFieldDataOneItem,
+ ItemIDs,
+ ItemIDsWithLocales,
+ ItemsCreateItemLiveRequestBody,
+ ItemsCreateItemRequestBody,
+ ItemsDeleteItemsLiveRequestItemsItem,
+ ItemsDeleteItemsRequestItemsItem,
+ ItemsListItemsLiveRequestSortBy,
+ ItemsListItemsLiveRequestSortOrder,
+ ItemsListItemsRequestSortBy,
+ ItemsListItemsRequestSortOrder,
+ ItemsPublishItemRequest,
+ ItemsPublishItemRequestItemsItemsItem,
+ ItemsPublishItemResponse,
+ ItemsUpdateItemsResponse,
+ MultipleItems,
+ MultipleLiveItems,
+ SingleCmsItem,
+ fields,
+ items,
+ )
+_dynamic_imports: typing.Dict[str, str] = {
+ "CreateBulkCollectionItemRequestBodyFieldData": ".resources",
+ "CreateBulkCollectionItemRequestBodyFieldDataOneItem": ".resources",
+ "ItemIDs": ".resources",
+ "ItemIDsWithLocales": ".resources",
+ "ItemsCreateItemLiveRequestBody": ".resources",
+ "ItemsCreateItemRequestBody": ".resources",
+ "ItemsDeleteItemsLiveRequestItemsItem": ".resources",
+ "ItemsDeleteItemsRequestItemsItem": ".resources",
+ "ItemsListItemsLiveRequestSortBy": ".resources",
+ "ItemsListItemsLiveRequestSortOrder": ".resources",
+ "ItemsListItemsRequestSortBy": ".resources",
+ "ItemsListItemsRequestSortOrder": ".resources",
+ "ItemsPublishItemRequest": ".resources",
+ "ItemsPublishItemRequestItemsItemsItem": ".resources",
+ "ItemsPublishItemResponse": ".resources",
+ "ItemsUpdateItemsResponse": ".resources",
+ "MultipleItems": ".resources",
+ "MultipleLiveItems": ".resources",
+ "SingleCmsItem": ".resources",
+ "fields": ".resources",
+ "items": ".resources",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = [
+ "CreateBulkCollectionItemRequestBodyFieldData",
+ "CreateBulkCollectionItemRequestBodyFieldDataOneItem",
+ "ItemIDs",
+ "ItemIDsWithLocales",
+ "ItemsCreateItemLiveRequestBody",
+ "ItemsCreateItemRequestBody",
+ "ItemsDeleteItemsLiveRequestItemsItem",
+ "ItemsDeleteItemsRequestItemsItem",
+ "ItemsListItemsLiveRequestSortBy",
+ "ItemsListItemsLiveRequestSortOrder",
+ "ItemsListItemsRequestSortBy",
+ "ItemsListItemsRequestSortOrder",
+ "ItemsPublishItemRequest",
+ "ItemsPublishItemRequestItemsItemsItem",
+ "ItemsPublishItemResponse",
+ "ItemsUpdateItemsResponse",
+ "MultipleItems",
+ "MultipleLiveItems",
+ "SingleCmsItem",
+ "fields",
+ "items",
+]
diff --git a/src/webflow/resources/collections/client.py b/src/webflow/resources/collections/client.py
index 669cb06..bd4adca 100644
--- a/src/webflow/resources/collections/client.py
+++ b/src/webflow/resources/collections/client.py
@@ -1,94 +1,73 @@
# This file was auto-generated by Fern from our API Definition.
+from __future__ import annotations
+
import typing
-import urllib.parse
-from json.decoder import JSONDecodeError
-from ...core.api_error import ApiError
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from ...core.jsonable_encoder import jsonable_encoder
-from ...core.remove_none_from_dict import remove_none_from_dict
from ...core.request_options import RequestOptions
-from ...errors.bad_request_error import BadRequestError
-from ...errors.internal_server_error import InternalServerError
-from ...errors.not_found_error import NotFoundError
-from ...errors.too_many_requests_error import TooManyRequestsError
-from ...errors.unauthorized_error import UnauthorizedError
from ...types.collection import Collection
from ...types.collection_list import CollectionList
-from .resources.fields.client import AsyncFieldsClient, FieldsClient
-from .resources.items.client import AsyncItemsClient, ItemsClient
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+from ...types.field_create import FieldCreate
+from .raw_client import AsyncRawCollectionsClient, RawCollectionsClient
+if typing.TYPE_CHECKING:
+ from .resources.fields.client import AsyncFieldsClient, FieldsClient
+ from .resources.items.client import AsyncItemsClient, ItemsClient
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
class CollectionsClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._raw_client = RawCollectionsClient(client_wrapper=client_wrapper)
self._client_wrapper = client_wrapper
- self.fields = FieldsClient(client_wrapper=self._client_wrapper)
- self.items = ItemsClient(client_wrapper=self._client_wrapper)
+ self._fields: typing.Optional[FieldsClient] = None
+ self._items: typing.Optional[ItemsClient] = None
+
+ @property
+ def with_raw_response(self) -> RawCollectionsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawCollectionsClient
+ """
+ return self._raw_client
def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> CollectionList:
"""
- List of all Collections within a Site. Required scope | `cms:read`
+ List of all Collections within a Site.
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Required scope | `cms:read`
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ CollectionList
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.collections.list(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/collections"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(CollectionList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.list(site_id, request_options=request_options)
+ return _response.data
def create(
self,
@@ -97,317 +76,228 @@ 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. Required scope | `cms:write`
+ 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.
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Required scope | `cms:write`
- - display_name: str. Name of the collection. Each collection name must be distinct.
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- - singular_name: str. Singular name of each item.
+ display_name : str
+ Name of the collection. Each collection name must be distinct.
- - slug: typing.Optional[str]. Part of a URL that identifier
+ singular_name : str
+ Singular name of each item.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ 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.
+
+ Returns
+ -------
+ Collection
+ Request was successful
+
+ Examples
+ --------
+ from webflow import ReferenceField, ReferenceFieldMetadata, StaticField, Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.collections.create(
- site_id="site_id",
+ 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",
+ ),
+ ),
+ ],
)
"""
- _request: typing.Dict[str, typing.Any] = {"displayName": display_name, "singularName": singular_name}
- if slug is not OMIT:
- _request["slug"] = slug
- _response = self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/collections"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.create(
+ site_id,
+ display_name=display_name,
+ singular_name=singular_name,
+ slug=slug,
+ fields=fields,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Collection, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
def get(self, collection_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Collection:
"""
- Get the full details of a collection from its ID. Required scope | `cms:read`
+ Get the full details of a collection from its ID.
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ Required scope | `cms:read`
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
- client = Webflow(
- access_token="YOUR_ACCESS_TOKEN",
- )
- client.collections.get(
- collection_id="collection_id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"collections/{jsonable_encoder(collection_id)}"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Collection, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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_collection(self, collection_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
- """
- Delete a collection using its ID. Required scope | `cms:write`
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ Returns
+ -------
+ Collection
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
- client.collections.delete_collection(
- collection_id="collection_id",
+ client.collections.get(
+ collection_id="580e63fc8c9a982ac9b8b745",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "DELETE",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"collections/{jsonable_encoder(collection_id)}"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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, collection_id: str, field_id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> None:
+ _response = self._raw_client.get(collection_id, request_options=request_options)
+ return _response.data
+
+ def delete(self, collection_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
"""
- Delete a custom field in a collection. This endpoint does not currently support bulk deletion. Required scope | `cms:write`
+ Delete a collection using its ID.
+
+ Required scope | `cms:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - field_id: str. Unique identifier for a Field in a collection
+ Returns
+ -------
+ None
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.collections.delete(
- collection_id="collection_id",
- field_id="field_id",
+ collection_id="580e63fc8c9a982ac9b8b745",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "DELETE",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"collections/{jsonable_encoder(collection_id)}/fields/{jsonable_encoder(field_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.delete(collection_id, request_options=request_options)
+ return _response.data
+
+ @property
+ def fields(self):
+ if self._fields is None:
+ from .resources.fields.client import FieldsClient # noqa: E402
+
+ self._fields = FieldsClient(client_wrapper=self._client_wrapper)
+ return self._fields
+
+ @property
+ def items(self):
+ if self._items is None:
+ from .resources.items.client import ItemsClient # noqa: E402
+
+ self._items = ItemsClient(client_wrapper=self._client_wrapper)
+ return self._items
class AsyncCollectionsClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._raw_client = AsyncRawCollectionsClient(client_wrapper=client_wrapper)
self._client_wrapper = client_wrapper
- self.fields = AsyncFieldsClient(client_wrapper=self._client_wrapper)
- self.items = AsyncItemsClient(client_wrapper=self._client_wrapper)
+ self._fields: typing.Optional[AsyncFieldsClient] = None
+ self._items: typing.Optional[AsyncItemsClient] = None
+
+ @property
+ def with_raw_response(self) -> AsyncRawCollectionsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawCollectionsClient
+ """
+ return self._raw_client
async def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> CollectionList:
"""
- List of all Collections within a Site. Required scope | `cms:read`
+ List of all Collections within a Site.
+
+ Required scope | `cms:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- Parameters:
- - site_id: str. Unique identifier for a Site
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Returns
+ -------
+ CollectionList
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.collections.list(
- site_id="site_id",
- )
+
+
+ async def main() -> None:
+ await client.collections.list(
+ site_id="580e63e98c9a982ac9b8b741",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/collections"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(CollectionList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.list(site_id, request_options=request_options)
+ return _response.data
async def create(
self,
@@ -416,253 +306,194 @@ 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. Required scope | `cms:write`
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- Parameters:
- - site_id: str. Unique identifier for a Site
+ display_name : str
+ Name of the collection. Each collection name must be distinct.
- - display_name: str. Name of the collection. Each collection name must be distinct.
+ singular_name : str
+ Singular name of each item.
- - singular_name: str. Singular name of each item.
+ slug : typing.Optional[str]
+ Part of a URL that identifier
- - 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.
- ---
- from webflow.client import AsyncWebflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Collection
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import (
+ AsyncWebflow,
+ ReferenceField,
+ ReferenceFieldMetadata,
+ StaticField,
+ )
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.collections.create(
- site_id="site_id",
- display_name="Blog Posts",
- singular_name="Blog Post",
- slug="posts",
- )
+
+
+ async def main() -> None:
+ await client.collections.create(
+ 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",
+ ),
+ ),
+ ],
+ )
+
+
+ asyncio.run(main())
"""
- _request: typing.Dict[str, typing.Any] = {"displayName": display_name, "singularName": singular_name}
- if slug is not OMIT:
- _request["slug"] = slug
- _response = await self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/collections"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.create(
+ site_id,
+ display_name=display_name,
+ singular_name=singular_name,
+ slug=slug,
+ fields=fields,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Collection, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
async def get(self, collection_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Collection:
"""
- Get the full details of a collection from its ID. Required scope | `cms:read`
+ Get the full details of a collection from its ID.
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ Required scope | `cms:read`
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
- client = AsyncWebflow(
- access_token="YOUR_ACCESS_TOKEN",
- )
- await client.collections.get(
- collection_id="collection_id",
- )
- """
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"collections/{jsonable_encoder(collection_id)}"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Collection, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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_collection(
- self, collection_id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> None:
- """
- Delete a collection using its ID. Required scope | `cms:write`
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Collection
+ Request was successful
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ Examples
+ --------
+ import asyncio
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.collections.delete_collection(
- collection_id="collection_id",
- )
+
+
+ async def main() -> None:
+ await client.collections.get(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "DELETE",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"collections/{jsonable_encoder(collection_id)}"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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, collection_id: str, field_id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> None:
+ _response = await self._raw_client.get(collection_id, request_options=request_options)
+ return _response.data
+
+ async def delete(self, collection_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
"""
- Delete a custom field in a collection. This endpoint does not currently support bulk deletion. Required scope | `cms:write`
+ Delete a collection using its ID.
+
+ Required scope | `cms:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - field_id: str. Unique identifier for a Field in a collection
+ Returns
+ -------
+ None
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.collections.delete(
- collection_id="collection_id",
- field_id="field_id",
- )
+
+
+ async def main() -> None:
+ await client.collections.delete(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "DELETE",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"collections/{jsonable_encoder(collection_id)}/fields/{jsonable_encoder(field_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.delete(collection_id, request_options=request_options)
+ return _response.data
+
+ @property
+ def fields(self):
+ if self._fields is None:
+ from .resources.fields.client import AsyncFieldsClient # noqa: E402
+
+ self._fields = AsyncFieldsClient(client_wrapper=self._client_wrapper)
+ return self._fields
+
+ @property
+ def items(self):
+ if self._items is None:
+ from .resources.items.client import AsyncItemsClient # noqa: E402
+
+ self._items = AsyncItemsClient(client_wrapper=self._client_wrapper)
+ return self._items
diff --git a/src/webflow/resources/collections/raw_client.py b/src/webflow/resources/collections/raw_client.py
new file mode 100644
index 0000000..ffc8451
--- /dev/null
+++ b/src/webflow/resources/collections/raw_client.py
@@ -0,0 +1,917 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from ...core.api_error import ApiError
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.http_response import AsyncHttpResponse, HttpResponse
+from ...core.jsonable_encoder import jsonable_encoder
+from ...core.parse_error import ParsingError
+from ...core.pydantic_utilities import parse_obj_as
+from ...core.request_options import RequestOptions
+from ...core.serialization import convert_and_respect_annotation_metadata
+from ...errors.bad_request_error import BadRequestError
+from ...errors.conflict_error import ConflictError
+from ...errors.internal_server_error import InternalServerError
+from ...errors.not_found_error import NotFoundError
+from ...errors.too_many_requests_error import TooManyRequestsError
+from ...errors.unauthorized_error import UnauthorizedError
+from ...types.collection import Collection
+from ...types.collection_list import CollectionList
+from ...types.error import Error
+from ...types.field_create import FieldCreate
+from pydantic import ValidationError
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RawCollectionsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def list(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[CollectionList]:
+ """
+ List of all Collections within a Site.
+
+ Required scope | `cms:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[CollectionList]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CollectionList,
+ parse_obj_as(
+ type_=CollectionList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def create(
+ self,
+ site_id: str,
+ *,
+ display_name: str,
+ singular_name: str,
+ slug: typing.Optional[str] = OMIT,
+ fields: typing.Optional[typing.Sequence[FieldCreate]] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[Collection]:
+ """
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ display_name : str
+ Name of the collection. Each collection name must be distinct.
+
+ singular_name : str
+ Singular name of each item.
+
+ 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.
+
+ Returns
+ -------
+ HttpResponse[Collection]
+ Request was successful
+ """
+ _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",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Collection,
+ parse_obj_as(
+ type_=Collection, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def get(
+ self, collection_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[Collection]:
+ """
+ Get the full details of a collection from its ID.
+
+ Required scope | `cms:read`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Collection]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Collection,
+ parse_obj_as(
+ type_=Collection, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def delete(
+ self, collection_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[None]:
+ """
+ Delete a collection using its ID.
+
+ Required scope | `cms:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[None]
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return HttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawCollectionsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def list(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[CollectionList]:
+ """
+ List of all Collections within a Site.
+
+ Required scope | `cms:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[CollectionList]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CollectionList,
+ parse_obj_as(
+ type_=CollectionList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def create(
+ self,
+ site_id: str,
+ *,
+ display_name: str,
+ singular_name: str,
+ slug: typing.Optional[str] = OMIT,
+ fields: typing.Optional[typing.Sequence[FieldCreate]] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[Collection]:
+ """
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ display_name : str
+ Name of the collection. Each collection name must be distinct.
+
+ singular_name : str
+ Singular name of each item.
+
+ 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.
+
+ Returns
+ -------
+ AsyncHttpResponse[Collection]
+ Request was successful
+ """
+ _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",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Collection,
+ parse_obj_as(
+ type_=Collection, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def get(
+ self, collection_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[Collection]:
+ """
+ Get the full details of a collection from its ID.
+
+ Required scope | `cms:read`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Collection]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Collection,
+ parse_obj_as(
+ type_=Collection, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def delete(
+ self, collection_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[None]:
+ """
+ Delete a collection using its ID.
+
+ Required scope | `cms:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return AsyncHttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/collections/resources/__init__.py b/src/webflow/resources/collections/resources/__init__.py
index 5b63931..7123bf3 100644
--- a/src/webflow/resources/collections/resources/__init__.py
+++ b/src/webflow/resources/collections/resources/__init__.py
@@ -1,7 +1,99 @@
# This file was auto-generated by Fern from our API Definition.
-from . import fields, items
-from .fields import FieldCreateType
-from .items import BulkCollectionItemFieldData, ItemsPublishItemResponse
+# isort: skip_file
-__all__ = ["BulkCollectionItemFieldData", "FieldCreateType", "ItemsPublishItemResponse", "fields", "items"]
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from . import fields, items
+ from .items import (
+ CreateBulkCollectionItemRequestBodyFieldData,
+ CreateBulkCollectionItemRequestBodyFieldDataOneItem,
+ ItemIDs,
+ ItemIDsWithLocales,
+ ItemsCreateItemLiveRequestBody,
+ ItemsCreateItemRequestBody,
+ ItemsDeleteItemsLiveRequestItemsItem,
+ ItemsDeleteItemsRequestItemsItem,
+ ItemsListItemsLiveRequestSortBy,
+ ItemsListItemsLiveRequestSortOrder,
+ ItemsListItemsRequestSortBy,
+ ItemsListItemsRequestSortOrder,
+ ItemsPublishItemRequest,
+ ItemsPublishItemRequestItemsItemsItem,
+ ItemsPublishItemResponse,
+ ItemsUpdateItemsResponse,
+ MultipleItems,
+ MultipleLiveItems,
+ SingleCmsItem,
+ )
+_dynamic_imports: typing.Dict[str, str] = {
+ "CreateBulkCollectionItemRequestBodyFieldData": ".items",
+ "CreateBulkCollectionItemRequestBodyFieldDataOneItem": ".items",
+ "ItemIDs": ".items",
+ "ItemIDsWithLocales": ".items",
+ "ItemsCreateItemLiveRequestBody": ".items",
+ "ItemsCreateItemRequestBody": ".items",
+ "ItemsDeleteItemsLiveRequestItemsItem": ".items",
+ "ItemsDeleteItemsRequestItemsItem": ".items",
+ "ItemsListItemsLiveRequestSortBy": ".items",
+ "ItemsListItemsLiveRequestSortOrder": ".items",
+ "ItemsListItemsRequestSortBy": ".items",
+ "ItemsListItemsRequestSortOrder": ".items",
+ "ItemsPublishItemRequest": ".items",
+ "ItemsPublishItemRequestItemsItemsItem": ".items",
+ "ItemsPublishItemResponse": ".items",
+ "ItemsUpdateItemsResponse": ".items",
+ "MultipleItems": ".items",
+ "MultipleLiveItems": ".items",
+ "SingleCmsItem": ".items",
+ "fields": ".fields",
+ "items": ".items",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = [
+ "CreateBulkCollectionItemRequestBodyFieldData",
+ "CreateBulkCollectionItemRequestBodyFieldDataOneItem",
+ "ItemIDs",
+ "ItemIDsWithLocales",
+ "ItemsCreateItemLiveRequestBody",
+ "ItemsCreateItemRequestBody",
+ "ItemsDeleteItemsLiveRequestItemsItem",
+ "ItemsDeleteItemsRequestItemsItem",
+ "ItemsListItemsLiveRequestSortBy",
+ "ItemsListItemsLiveRequestSortOrder",
+ "ItemsListItemsRequestSortBy",
+ "ItemsListItemsRequestSortOrder",
+ "ItemsPublishItemRequest",
+ "ItemsPublishItemRequestItemsItemsItem",
+ "ItemsPublishItemResponse",
+ "ItemsUpdateItemsResponse",
+ "MultipleItems",
+ "MultipleLiveItems",
+ "SingleCmsItem",
+ "fields",
+ "items",
+]
diff --git a/src/webflow/resources/collections/resources/fields/__init__.py b/src/webflow/resources/collections/resources/fields/__init__.py
index 5a5b167..5cde020 100644
--- a/src/webflow/resources/collections/resources/fields/__init__.py
+++ b/src/webflow/resources/collections/resources/fields/__init__.py
@@ -1,5 +1,4 @@
# This file was auto-generated by Fern from our API Definition.
-from .types import FieldCreateType
+# isort: skip_file
-__all__ = ["FieldCreateType"]
diff --git a/src/webflow/resources/collections/resources/fields/client.py b/src/webflow/resources/collections/resources/fields/client.py
index 9622f64..b4f337b 100644
--- a/src/webflow/resources/collections/resources/fields/client.py
+++ b/src/webflow/resources/collections/resources/fields/client.py
@@ -1,26 +1,12 @@
# This file was auto-generated by Fern from our API Definition.
import typing
-import urllib.parse
-from json.decoder import JSONDecodeError
-from .....core.api_error import ApiError
from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from .....core.jsonable_encoder import jsonable_encoder
-from .....core.remove_none_from_dict import remove_none_from_dict
from .....core.request_options import RequestOptions
-from .....errors.bad_request_error import BadRequestError
-from .....errors.internal_server_error import InternalServerError
-from .....errors.not_found_error import NotFoundError
-from .....errors.too_many_requests_error import TooManyRequestsError
-from .....errors.unauthorized_error import UnauthorizedError
from .....types.field import Field
-from .types.field_create_type import FieldCreateType
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+from .....types.field_create import FieldCreate
+from .raw_client import AsyncRawFieldsClient, RawFieldsClient
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
@@ -28,96 +14,105 @@
class FieldsClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = RawFieldsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawFieldsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawFieldsClient
+ """
+ return self._raw_client
def create(
- self,
- collection_id: str,
- *,
- is_required: typing.Optional[bool] = OMIT,
- type: FieldCreateType,
- display_name: str,
- 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 "-." Only some field types can be created through the API. This endpoint does not currently support bulk creation. Required scope | `cms:write`
+ Create a custom field in a collection.
+
+ Field validation is currently not available through the API.
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ 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)
- - is_required: typing.Optional[bool]. define whether a field is required in a collection
+ Required scope | `cms:write`
- - type: FieldCreateType. Choose these appropriate field type for your collection data
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
- - display_name: str. The name of a field
+ request : FieldCreate
- - help_text: typing.Optional[str]. Additional text to help anyone filling out this field
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
- from webflow.resources.collections import FieldCreateType
+ Returns
+ -------
+ FieldCreate
+ Request was successful
+
+ Examples
+ --------
+ from webflow import StaticField, Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.collections.fields.create(
- collection_id="collection_id",
- is_required=False,
- type=FieldCreateType.RICH_TEXT,
- display_name="Post Body",
- help_text="Add the body of your post here",
+ collection_id="580e63fc8c9a982ac9b8b745",
+ request=StaticField(
+ id="562ac0395358780a1f5e6fbc",
+ is_editable=True,
+ is_required=False,
+ type="RichText",
+ display_name="Post Body",
+ help_text="Add the body of your post here",
+ ),
)
"""
- _request: typing.Dict[str, typing.Any] = {"type": type, "displayName": display_name}
- if is_required is not OMIT:
- _request["isRequired"] = is_required
- if help_text is not OMIT:
- _request["helpText"] = help_text
- _response = self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"collections/{jsonable_encoder(collection_id)}/fields"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.create(collection_id, request=request, request_options=request_options)
+ return _response.data
+
+ def delete(
+ self, collection_id: str, field_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> None:
+ """
+ Delete a custom field in a collection. This endpoint does not currently support bulk deletion.
+
+ Required scope | `cms:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ field_id : str
+ Unique identifier for a Field in a collection
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ from webflow import Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.collections.fields.delete(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ field_id="580e63fc8c9a982ac9b8b745",
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Field, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ """
+ _response = self._raw_client.delete(collection_id, field_id, request_options=request_options)
+ return _response.data
def update(
self,
@@ -130,179 +125,178 @@ def update(
request_options: typing.Optional[RequestOptions] = None,
) -> Field:
"""
- Update a custom field in a collection. Required scope | `cms:write`
+ Update a custom field in a collection.
+
+ Required scope | `cms:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ field_id : str
+ Unique identifier for a Field in a collection
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ is_required : typing.Optional[bool]
+ Define whether a field is required in a collection
- - field_id: str. Unique identifier for a Field in a collection
+ display_name : typing.Optional[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
- - display_name: typing.Optional[str]. The name of a field
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - help_text: typing.Optional[str]. Additional text to help anyone filling out this field
+ Returns
+ -------
+ Field
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.collections.fields.update(
- collection_id="collection_id",
- field_id="field_id",
+ collection_id="580e63fc8c9a982ac9b8b745",
+ field_id="580e63fc8c9a982ac9b8b745",
is_required=False,
display_name="Post Body",
help_text="Add the body of your post here",
)
"""
- _request: typing.Dict[str, typing.Any] = {}
- if is_required is not OMIT:
- _request["isRequired"] = is_required
- if display_name is not OMIT:
- _request["displayName"] = display_name
- if help_text is not OMIT:
- _request["helpText"] = help_text
- _response = self._client_wrapper.httpx_client.request(
- "PATCH",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"collections/{jsonable_encoder(collection_id)}/fields/{jsonable_encoder(field_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.update(
+ collection_id,
+ field_id,
+ is_required=is_required,
+ display_name=display_name,
+ help_text=help_text,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Field, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
class AsyncFieldsClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = AsyncRawFieldsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawFieldsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawFieldsClient
+ """
+ return self._raw_client
async def create(
- self,
- collection_id: str,
- *,
- is_required: typing.Optional[bool] = OMIT,
- type: FieldCreateType,
- display_name: str,
- 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 "-." Only some field types can be created through the API. This endpoint does not currently support bulk creation. Required scope | `cms:write`
+ Create a custom field in a collection.
+
+ Field validation is currently not available through the API.
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ 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)
- - is_required: typing.Optional[bool]. define whether a field is required in a collection
+ Required scope | `cms:write`
- - type: FieldCreateType. Choose these appropriate field type for your collection data
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
- - display_name: str. The name of a field
+ request : FieldCreate
- - help_text: typing.Optional[str]. Additional text to help anyone filling out this field
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
- from webflow.resources.collections import FieldCreateType
+ Returns
+ -------
+ FieldCreate
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow, StaticField
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.collections.fields.create(
- collection_id="collection_id",
- is_required=False,
- type=FieldCreateType.RICH_TEXT,
- display_name="Post Body",
- help_text="Add the body of your post here",
- )
+
+
+ async def main() -> None:
+ await client.collections.fields.create(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ request=StaticField(
+ id="562ac0395358780a1f5e6fbc",
+ is_editable=True,
+ is_required=False,
+ type="RichText",
+ display_name="Post Body",
+ help_text="Add the body of your post here",
+ ),
+ )
+
+
+ asyncio.run(main())
"""
- _request: typing.Dict[str, typing.Any] = {"type": type, "displayName": display_name}
- if is_required is not OMIT:
- _request["isRequired"] = is_required
- if help_text is not OMIT:
- _request["helpText"] = help_text
- _response = await self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"collections/{jsonable_encoder(collection_id)}/fields"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.create(collection_id, request=request, request_options=request_options)
+ return _response.data
+
+ async def delete(
+ self, collection_id: str, field_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> None:
+ """
+ Delete a custom field in a collection. This endpoint does not currently support bulk deletion.
+
+ Required scope | `cms:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ field_id : str
+ Unique identifier for a Field in a collection
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Field, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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 main() -> None:
+ await client.collections.fields.delete(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ field_id="580e63fc8c9a982ac9b8b745",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.delete(collection_id, field_id, request_options=request_options)
+ return _response.data
async def update(
self,
@@ -315,82 +309,64 @@ async def update(
request_options: typing.Optional[RequestOptions] = None,
) -> Field:
"""
- Update a custom field in a collection. Required scope | `cms:write`
+ Update a custom field in a collection.
+
+ Required scope | `cms:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ field_id : str
+ Unique identifier for a Field in a collection
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ is_required : typing.Optional[bool]
+ Define whether a field is required in a collection
- - field_id: str. Unique identifier for a Field in a collection
+ display_name : typing.Optional[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
- - display_name: typing.Optional[str]. The name of a field
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - help_text: typing.Optional[str]. Additional text to help anyone filling out this field
+ Returns
+ -------
+ Field
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.collections.fields.update(
- collection_id="collection_id",
- field_id="field_id",
- is_required=False,
- display_name="Post Body",
- help_text="Add the body of your post here",
- )
+
+
+ async def main() -> None:
+ await client.collections.fields.update(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ field_id="580e63fc8c9a982ac9b8b745",
+ is_required=False,
+ display_name="Post Body",
+ help_text="Add the body of your post here",
+ )
+
+
+ asyncio.run(main())
"""
- _request: typing.Dict[str, typing.Any] = {}
- if is_required is not OMIT:
- _request["isRequired"] = is_required
- if display_name is not OMIT:
- _request["displayName"] = display_name
- if help_text is not OMIT:
- _request["helpText"] = help_text
- _response = await self._client_wrapper.httpx_client.request(
- "PATCH",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"collections/{jsonable_encoder(collection_id)}/fields/{jsonable_encoder(field_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.update(
+ collection_id,
+ field_id,
+ is_required=is_required,
+ display_name=display_name,
+ help_text=help_text,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Field, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
diff --git a/src/webflow/resources/collections/resources/fields/raw_client.py b/src/webflow/resources/collections/resources/fields/raw_client.py
new file mode 100644
index 0000000..31f26be
--- /dev/null
+++ b/src/webflow/resources/collections/resources/fields/raw_client.py
@@ -0,0 +1,732 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from .....core.api_error import ApiError
+from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .....core.http_response import AsyncHttpResponse, HttpResponse
+from .....core.jsonable_encoder import jsonable_encoder
+from .....core.parse_error import ParsingError
+from .....core.pydantic_utilities import parse_obj_as
+from .....core.request_options import RequestOptions
+from .....core.serialization import convert_and_respect_annotation_metadata
+from .....errors.bad_request_error import BadRequestError
+from .....errors.conflict_error import ConflictError
+from .....errors.internal_server_error import InternalServerError
+from .....errors.not_found_error import NotFoundError
+from .....errors.too_many_requests_error import TooManyRequestsError
+from .....errors.unauthorized_error import UnauthorizedError
+from .....types.error import Error
+from .....types.field import Field
+from .....types.field_create import FieldCreate
+from pydantic import ValidationError
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RawFieldsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def create(
+ self, collection_id: str, *, request: FieldCreate, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[FieldCreate]:
+ """
+ Create a custom field in a collection.
+
+ Field validation is currently not available through the API.
+
+ Bulk creation of fields is not supported with this endpoint. To add multiple fields at once, include them when you [create the collection.](/data/v2.0.0/reference/cms/collections/create)
+
+ Required scope | `cms:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ request : FieldCreate
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[FieldCreate]
+ Request was successful
+ """
+ _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=convert_and_respect_annotation_metadata(object_=request, annotation=FieldCreate, direction="write"),
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ FieldCreate,
+ parse_obj_as(
+ type_=FieldCreate, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def delete(
+ self, collection_id: str, field_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[None]:
+ """
+ Delete a custom field in a collection. This endpoint does not currently support bulk deletion.
+
+ Required scope | `cms:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ field_id : str
+ Unique identifier for a Field in a collection
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[None]
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return HttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def update(
+ self,
+ collection_id: str,
+ field_id: str,
+ *,
+ is_required: typing.Optional[bool] = OMIT,
+ display_name: typing.Optional[str] = OMIT,
+ help_text: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[Field]:
+ """
+ Update a custom field in a collection.
+
+ Required scope | `cms:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ field_id : str
+ Unique identifier for a Field in a collection
+
+ is_required : typing.Optional[bool]
+ Define whether a field is required in a collection
+
+ display_name : typing.Optional[str]
+ The name of a field
+
+ help_text : typing.Optional[str]
+ Additional text to help anyone filling out this field
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Field]
+ Request was successful
+ """
+ _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,
+ "displayName": display_name,
+ "helpText": help_text,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Field,
+ parse_obj_as(
+ type_=Field, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawFieldsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def create(
+ self, collection_id: str, *, request: FieldCreate, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[FieldCreate]:
+ """
+ Create a custom field in a collection.
+
+ Field validation is currently not available through the API.
+
+ Bulk creation of fields is not supported with this endpoint. To add multiple fields at once, include them when you [create the collection.](/data/v2.0.0/reference/cms/collections/create)
+
+ Required scope | `cms:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ request : FieldCreate
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[FieldCreate]
+ Request was successful
+ """
+ _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=convert_and_respect_annotation_metadata(object_=request, annotation=FieldCreate, direction="write"),
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ FieldCreate,
+ parse_obj_as(
+ type_=FieldCreate, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def delete(
+ self, collection_id: str, field_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[None]:
+ """
+ Delete a custom field in a collection. This endpoint does not currently support bulk deletion.
+
+ Required scope | `cms:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ field_id : str
+ Unique identifier for a Field in a collection
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return AsyncHttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def update(
+ self,
+ collection_id: str,
+ field_id: str,
+ *,
+ is_required: typing.Optional[bool] = OMIT,
+ display_name: typing.Optional[str] = OMIT,
+ help_text: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[Field]:
+ """
+ Update a custom field in a collection.
+
+ Required scope | `cms:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ field_id : str
+ Unique identifier for a Field in a collection
+
+ is_required : typing.Optional[bool]
+ Define whether a field is required in a collection
+
+ display_name : typing.Optional[str]
+ The name of a field
+
+ help_text : typing.Optional[str]
+ Additional text to help anyone filling out this field
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Field]
+ Request was successful
+ """
+ _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,
+ "displayName": display_name,
+ "helpText": help_text,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Field,
+ parse_obj_as(
+ type_=Field, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/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/fields/types/field_create_type.py b/src/webflow/resources/collections/resources/fields/types/field_create_type.py
deleted file mode 100644
index db7db4a..0000000
--- a/src/webflow/resources/collections/resources/fields/types/field_create_type.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import enum
-import typing
-
-T_Result = typing.TypeVar("T_Result")
-
-
-class FieldCreateType(str, enum.Enum):
- """
- Choose these appropriate field type for your collection data
- """
-
- PLAIN_TEXT = "PlainText"
- RICH_TEXT = "RichText"
- IMAGE = "Image"
- MULTI_IMAGE = "MultiImage"
- VIDEO = "Video"
- LINK = "Link"
- EMAIL = "Email"
- PHONE = "Phone"
- NUMBER = "Number"
- DATE_TIME = "DateTime"
- BOOLEAN = "Boolean"
- COLOR = "Color"
- FILE = "File"
-
- def visit(
- self,
- plain_text: typing.Callable[[], T_Result],
- rich_text: typing.Callable[[], T_Result],
- image: typing.Callable[[], T_Result],
- multi_image: typing.Callable[[], T_Result],
- video: typing.Callable[[], T_Result],
- link: typing.Callable[[], T_Result],
- email: typing.Callable[[], T_Result],
- phone: typing.Callable[[], T_Result],
- number: typing.Callable[[], T_Result],
- date_time: typing.Callable[[], T_Result],
- boolean: typing.Callable[[], T_Result],
- color: typing.Callable[[], T_Result],
- file: typing.Callable[[], T_Result],
- ) -> T_Result:
- if self is FieldCreateType.PLAIN_TEXT:
- return plain_text()
- if self is FieldCreateType.RICH_TEXT:
- return rich_text()
- if self is FieldCreateType.IMAGE:
- return image()
- if self is FieldCreateType.MULTI_IMAGE:
- return multi_image()
- if self is FieldCreateType.VIDEO:
- return video()
- if self is FieldCreateType.LINK:
- return link()
- if self is FieldCreateType.EMAIL:
- return email()
- if self is FieldCreateType.PHONE:
- return phone()
- if self is FieldCreateType.NUMBER:
- return number()
- if self is FieldCreateType.DATE_TIME:
- return date_time()
- if self is FieldCreateType.BOOLEAN:
- return boolean()
- if self is FieldCreateType.COLOR:
- return color()
- if self is FieldCreateType.FILE:
- return file()
diff --git a/src/webflow/resources/collections/resources/items/__init__.py b/src/webflow/resources/collections/resources/items/__init__.py
index f9fc28c..ae89439 100644
--- a/src/webflow/resources/collections/resources/items/__init__.py
+++ b/src/webflow/resources/collections/resources/items/__init__.py
@@ -1,5 +1,94 @@
# This file was auto-generated by Fern from our API Definition.
-from .types import BulkCollectionItemFieldData, ItemsPublishItemResponse
+# isort: skip_file
-__all__ = ["BulkCollectionItemFieldData", "ItemsPublishItemResponse"]
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .types import (
+ CreateBulkCollectionItemRequestBodyFieldData,
+ CreateBulkCollectionItemRequestBodyFieldDataOneItem,
+ ItemIDs,
+ ItemIDsWithLocales,
+ ItemsCreateItemLiveRequestBody,
+ ItemsCreateItemRequestBody,
+ ItemsDeleteItemsLiveRequestItemsItem,
+ ItemsDeleteItemsRequestItemsItem,
+ ItemsListItemsLiveRequestSortBy,
+ ItemsListItemsLiveRequestSortOrder,
+ ItemsListItemsRequestSortBy,
+ ItemsListItemsRequestSortOrder,
+ ItemsPublishItemRequest,
+ ItemsPublishItemRequestItemsItemsItem,
+ ItemsPublishItemResponse,
+ ItemsUpdateItemsResponse,
+ MultipleItems,
+ MultipleLiveItems,
+ SingleCmsItem,
+ )
+_dynamic_imports: typing.Dict[str, str] = {
+ "CreateBulkCollectionItemRequestBodyFieldData": ".types",
+ "CreateBulkCollectionItemRequestBodyFieldDataOneItem": ".types",
+ "ItemIDs": ".types",
+ "ItemIDsWithLocales": ".types",
+ "ItemsCreateItemLiveRequestBody": ".types",
+ "ItemsCreateItemRequestBody": ".types",
+ "ItemsDeleteItemsLiveRequestItemsItem": ".types",
+ "ItemsDeleteItemsRequestItemsItem": ".types",
+ "ItemsListItemsLiveRequestSortBy": ".types",
+ "ItemsListItemsLiveRequestSortOrder": ".types",
+ "ItemsListItemsRequestSortBy": ".types",
+ "ItemsListItemsRequestSortOrder": ".types",
+ "ItemsPublishItemRequest": ".types",
+ "ItemsPublishItemRequestItemsItemsItem": ".types",
+ "ItemsPublishItemResponse": ".types",
+ "ItemsUpdateItemsResponse": ".types",
+ "MultipleItems": ".types",
+ "MultipleLiveItems": ".types",
+ "SingleCmsItem": ".types",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = [
+ "CreateBulkCollectionItemRequestBodyFieldData",
+ "CreateBulkCollectionItemRequestBodyFieldDataOneItem",
+ "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 21e4df3..16f1d5c 100644
--- a/src/webflow/resources/collections/resources/items/client.py
+++ b/src/webflow/resources/collections/resources/items/client.py
@@ -1,28 +1,30 @@
# This file was auto-generated by Fern from our API Definition.
import typing
-import urllib.parse
-from json.decoder import JSONDecodeError
-from .....core.api_error import ApiError
from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from .....core.jsonable_encoder import jsonable_encoder
-from .....core.remove_none_from_dict import remove_none_from_dict
from .....core.request_options import RequestOptions
-from .....errors.bad_request_error import BadRequestError
-from .....errors.internal_server_error import InternalServerError
-from .....errors.not_found_error import NotFoundError
-from .....errors.too_many_requests_error import TooManyRequestsError
-from .....errors.unauthorized_error import UnauthorizedError
+from .....types.bulk_collection_item import BulkCollectionItem
from .....types.collection_item import CollectionItem
from .....types.collection_item_list import CollectionItemList
-from .types.bulk_collection_item_field_data import BulkCollectionItemFieldData
+from .....types.collection_item_list_no_pagination import CollectionItemListNoPagination
+from .....types.collection_item_patch_single_field_data import CollectionItemPatchSingleFieldData
+from .....types.collection_item_with_id_input import CollectionItemWithIdInput
+from .....types.items_list_items_live_request_last_published import ItemsListItemsLiveRequestLastPublished
+from .....types.items_list_items_request_last_published import ItemsListItemsRequestLastPublished
+from .raw_client import AsyncRawItemsClient, RawItemsClient
+from .types.create_bulk_collection_item_request_body_field_data import CreateBulkCollectionItemRequestBodyFieldData
+from .types.items_create_item_live_request_body import ItemsCreateItemLiveRequestBody
+from .types.items_create_item_request_body import ItemsCreateItemRequestBody
+from .types.items_delete_items_live_request_items_item import ItemsDeleteItemsLiveRequestItemsItem
+from .types.items_delete_items_request_items_item import ItemsDeleteItemsRequestItemsItem
+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_list_items_request_sort_by import ItemsListItemsRequestSortBy
+from .types.items_list_items_request_sort_order import ItemsListItemsRequestSortOrder
+from .types.items_publish_item_request import ItemsPublishItemRequest
from .types.items_publish_item_response import ItemsPublishItemResponse
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+from .types.items_update_items_response import ItemsUpdateItemsResponse
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
@@ -30,1194 +32,684 @@
class ItemsClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = RawItemsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawItemsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawItemsClient
+ """
+ return self._raw_client
def list_items(
self,
collection_id: str,
*,
- cms_locale_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- offset: typing.Optional[float] = None,
- limit: typing.Optional[float] = None,
+ cms_locale_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ name: typing.Optional[str] = None,
+ slug: typing.Optional[str] = None,
+ last_published: typing.Optional[ItemsListItemsRequestLastPublished] = None,
+ sort_by: typing.Optional[ItemsListItemsRequestSortBy] = None,
+ sort_order: typing.Optional[ItemsListItemsRequestSortOrder] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> CollectionItemList:
"""
- List of all Items within a Collection. Required scope | `CMS:read`
+ List of all Items within a Collection.
+
+ Required scope | `CMS:read`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
- - cms_locale_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]]. Unique identifiers for CMS Locales. These UIDs are different from the Site locale identifier and are listed as `cmsLocaleId` in the Sites response. Applicable when using localization.
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
- - offset: typing.Optional[float]. Offset used for pagination if the results have more than limit records
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
- - limit: typing.Optional[float]. Maximum number of records to be returned (max limit: 100)
+ name : typing.Optional[str]
+ Filter by the exact name of the item(s)
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ slug : typing.Optional[str]
+ Filter by the exact slug of the item
+
+ last_published : typing.Optional[ItemsListItemsRequestLastPublished]
+ Filter by the last published date of the item(s)
+
+ sort_by : typing.Optional[ItemsListItemsRequestSortBy]
+ Sort results by the provided value
+
+ sort_order : typing.Optional[ItemsListItemsRequestSortOrder]
+ Sorts the results by asc or desc
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ CollectionItemList
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.collections.items.list_items(
- collection_id="collection_id",
+ collection_id="580e63fc8c9a982ac9b8b745",
+ cms_locale_id="cmsLocaleId",
+ offset=1,
+ limit=1,
+ name="name",
+ slug="slug",
+ sort_by="lastPublished",
+ sort_order="asc",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"collections/{jsonable_encoder(collection_id)}/items"
- ),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "cmsLocaleIds": cms_locale_ids,
- "offset": offset,
- "limit": limit,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(CollectionItemList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.list_items(
+ collection_id,
+ cms_locale_id=cms_locale_id,
+ offset=offset,
+ limit=limit,
+ name=name,
+ slug=slug,
+ last_published=last_published,
+ sort_by=sort_by,
+ sort_order=sort_order,
+ request_options=request_options,
+ )
+ return _response.data
def create_item(
- self, collection_id: str, *, request: CollectionItem, request_options: typing.Optional[RequestOptions] = None
- ) -> None:
+ self,
+ collection_id: str,
+ *,
+ request: ItemsCreateItemRequestBody,
+ skip_invalid_files: typing.Optional[bool] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> CollectionItem:
"""
- Create Item in a Collection. To create items across multiple locales, please use this endpoint. Required scope | `CMS:write`
+ Create Item(s) in a Collection.
- Parameters:
- - collection_id: str. Unique identifier for a Collection
- - request: CollectionItem.
+ To create items across multiple locales, please use [this endpoint.](/data/reference/cms/collection-items/staged-items/create-items)
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow import CollectionItem, CollectionItemFieldData
- from webflow.client import Webflow
+ Required scope | `CMS:write`
- client = Webflow(
- access_token="YOUR_ACCESS_TOKEN",
- )
- client.collections.items.create_item(
- collection_id="collection_id",
- request=CollectionItem(
- id="42b720ef280c7a7a3be8cabe",
- cms_locale_id="653ad57de882f528b32e810e",
- last_published="2022-11-29T16:22:43.159Z",
- last_updated="2022-11-17T17:19:43.282Z",
- created_on="2022-11-17T17:11:57.148Z",
- is_archived=False,
- is_draft=False,
- field_data=CollectionItemFieldData(
- name="Pan Galactic Gargle Blaster Recipe",
- slug="pan-galactic-gargle-blaster",
- ),
- ),
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"collections/{jsonable_encoder(collection_id)}/items"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
- def create_item_live(
- self, collection_id: str, *, request: CollectionItem, request_options: typing.Optional[RequestOptions] = None
- ) -> None:
- """
- Create live Item in a Collection. This Item will be published to the live site. To create items across multiple locales, please use this endpoint. Required scope | `CMS:write`
+ request : ItemsCreateItemRequestBody
- Parameters:
- - 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.
- - request: CollectionItem.
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow import CollectionItem, CollectionItemFieldData
- from webflow.client import Webflow
+ Returns
+ -------
+ CollectionItem
+ Request was successful
+
+ Examples
+ --------
+ from webflow import (
+ CollectionItemPostSingle,
+ CollectionItemPostSingleFieldData,
+ Webflow,
+ )
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
- client.collections.items.create_item_live(
- collection_id="collection_id",
- request=CollectionItem(
- id="42b720ef280c7a7a3be8cabe",
- cms_locale_id="653ad57de882f528b32e810e",
- last_published="2022-11-29T16:22:43.159Z",
- last_updated="2022-11-17T17:19:43.282Z",
- created_on="2022-11-17T17:11:57.148Z",
+ client.collections.items.create_item(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ skip_invalid_files=True,
+ request=CollectionItemPostSingle(
is_archived=False,
is_draft=False,
- field_data=CollectionItemFieldData(
- name="Pan Galactic Gargle Blaster Recipe",
- slug="pan-galactic-gargle-blaster",
+ field_data=CollectionItemPostSingleFieldData(
+ name="The Hitchhiker's Guide to the Galaxy",
+ slug="hitchhikers-guide-to-the-galaxy",
),
),
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"collections/{jsonable_encoder(collection_id)}/items/live"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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 create_item_for_multiple_locales(
+ _response = self._raw_client.create_item(
+ collection_id, request=request, skip_invalid_files=skip_invalid_files, request_options=request_options
+ )
+ return _response.data
+
+ def delete_items(
self,
collection_id: str,
*,
- id: str,
- cms_locale_ids: typing.Optional[typing.Sequence[str]] = OMIT,
- last_published: typing.Optional[str] = OMIT,
- last_updated: typing.Optional[str] = OMIT,
- created_on: typing.Optional[str] = OMIT,
- is_archived: typing.Optional[bool] = OMIT,
- is_draft: typing.Optional[bool] = OMIT,
- field_data: typing.Optional[BulkCollectionItemFieldData] = OMIT,
+ items: typing.Sequence[ItemsDeleteItemsRequestItemsItem],
request_options: typing.Optional[RequestOptions] = None,
) -> None:
"""
- Create single Item in a Collection with multiple corresponding locales. Required scope | `CMS:write`
+ Delete Items from a Collection.
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ Items will only be deleted in the primary locale unless a `cmsLocaleId` is included in the request.
- - id: str. Unique identifier for the Item
+ Required scope | `CMS:write`
- - cms_locale_ids: typing.Optional[typing.Sequence[str]]. Array of identifiers for the locales where the item will be created
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
- - last_published: typing.Optional[str]. The date the item was last published
+ items : typing.Sequence[ItemsDeleteItemsRequestItemsItem]
- - last_updated: typing.Optional[str]. The date the item was last updated
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - created_on: typing.Optional[str]. The date the item was created
+ Returns
+ -------
+ None
- - is_archived: typing.Optional[bool]. Boolean determining if the Item is set to archived
-
- - is_draft: typing.Optional[bool]. Boolean determining if the Item is set to draft
-
- - field_data: typing.Optional[BulkCollectionItemFieldData].
-
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
- from webflow.resources.collections import BulkCollectionItemFieldData
+ Examples
+ --------
+ from webflow import Webflow
+ from webflow.resources.collections.resources.items import (
+ ItemsDeleteItemsRequestItemsItem,
+ )
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
- client.collections.items.create_item_for_multiple_locales(
- collection_id="collection_id",
- id="580e64008c9a982ac9b8b754",
- last_published="2023-03-17T18:47:35.560Z",
- last_updated="2023-03-17T18:47:35.560Z",
- created_on="2023-03-17T18:47:35.560Z",
- field_data=BulkCollectionItemFieldData(
- name="My new item",
- slug="my-new-item",
- ),
+ client.collections.items.delete_items(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ items=[
+ ItemsDeleteItemsRequestItemsItem(
+ id="580e64008c9a982ac9b8b754",
+ )
+ ],
)
"""
- _request: typing.Dict[str, typing.Any] = {"id": id}
- if cms_locale_ids is not OMIT:
- _request["cmsLocaleIds"] = cms_locale_ids
- if last_published is not OMIT:
- _request["lastPublished"] = last_published
- if last_updated is not OMIT:
- _request["lastUpdated"] = last_updated
- if created_on is not OMIT:
- _request["createdOn"] = created_on
- if is_archived is not OMIT:
- _request["isArchived"] = is_archived
- if is_draft is not OMIT:
- _request["isDraft"] = is_draft
- if field_data is not OMIT:
- _request["fieldData"] = field_data
- _response = self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"collections/{jsonable_encoder(collection_id)}/items/bulk"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.delete_items(collection_id, items=items, request_options=request_options)
+ return _response.data
- def get_item(
+ def update_items(
self,
collection_id: str,
- item_id: str,
*,
- cms_locale_id: typing.Optional[str] = None,
+ skip_invalid_files: typing.Optional[bool] = None,
+ items: typing.Optional[typing.Sequence[CollectionItemWithIdInput]] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> CollectionItem:
+ ) -> ItemsUpdateItemsResponse:
"""
- Get details of a selected Collection Item. Required scope | `CMS:read`
+ Update a single item or multiple items in a Collection.
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ The limit for this endpoint is 100 items.
- - item_id: str. Unique identifier for an Item
+ Items will only be updated in the primary locale, unless a `cmsLocaleId` is included in the request.
- - cms_locale_id: typing.Optional[str]. Unique identifier for a CMS Locale. These UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. Applicable when using localization.
+ Required scope | `CMS:write`
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
-
- client = Webflow(
- access_token="YOUR_ACCESS_TOKEN",
- )
- client.collections.items.get_item(
- collection_id="collection_id",
- item_id="item_id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}",
- ),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "cmsLocaleId": cms_locale_id,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(CollectionItem, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
- def delete_item(
- self,
- collection_id: str,
- item_id: str,
- *,
- cms_locale_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> None:
- """
- Delete an Item from a Collection. This endpoint does not currently support bulk deletion. Required scope | `CMS:write`
+ 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.
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ items : typing.Optional[typing.Sequence[CollectionItemWithIdInput]]
- - item_id: str. Unique identifier for an Item
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - cms_locale_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]]. Unique identifiers for CMS Locales. These UIDs are different from the Site locale identifier and are listed as `cmsLocaleId` in the Sites response. Applicable when using localization.
+ Returns
+ -------
+ ItemsUpdateItemsResponse
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Examples
+ --------
+ from webflow import (
+ CollectionItemWithIdInput,
+ CollectionItemWithIdInputFieldData,
+ Webflow,
+ )
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
- client.collections.items.delete_item(
- collection_id="collection_id",
- item_id="item_id",
+ client.collections.items.update_items(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ skip_invalid_files=True,
+ items=[
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5ea6",
+ cms_locale_id="66f6e966c9e1dc700a857ca5",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="Ne Paniquez Pas",
+ slug="ne-paniquez-pas",
+ ),
+ ),
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5ea6",
+ cms_locale_id="66f6e966c9e1dc700a857ca4",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="No Entrar en Pánico",
+ slug="no-entrar-en-panico",
+ ),
+ ),
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5eaa",
+ cms_locale_id="66f6e966c9e1dc700a857ca5",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="Au Revoir et Merci pour Tous les Poissons",
+ slug="au-revoir-et-merci",
+ ),
+ ),
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5eaa",
+ cms_locale_id="66f6e966c9e1dc700a857ca4",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="Hasta Luego y Gracias por Todo el Pescado",
+ slug="hasta-luego-y-gracias",
+ ),
+ ),
+ ],
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "DELETE",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}",
- ),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "cmsLocaleIds": cms_locale_ids,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.update_items(
+ collection_id, skip_invalid_files=skip_invalid_files, items=items, request_options=request_options
+ )
+ return _response.data
- def update_item(
+ def list_items_live(
self,
collection_id: str,
- item_id: str,
*,
- request: CollectionItem,
+ cms_locale_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ name: typing.Optional[str] = None,
+ slug: typing.Optional[str] = None,
+ last_published: typing.Optional[ItemsListItemsLiveRequestLastPublished] = None,
+ sort_by: typing.Optional[ItemsListItemsLiveRequestSortBy] = None,
+ sort_order: typing.Optional[ItemsListItemsLiveRequestSortOrder] = None,
request_options: typing.Optional[RequestOptions] = None,
- ) -> CollectionItem:
+ ) -> CollectionItemList:
"""
- Update a selected Item in a Collection. Required scope | `CMS:write`
+ List all published items in a collection.
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+
+ Serving data to applications in real-time? Use the Content Delivery API at `api-cdn.webflow.com` for better performance. The CDN-backed endpoint is optimized for high-volume reads, while the Data API is designed for writes and management operations.
+
- - item_id: str. Unique identifier for an Item
+ Required scope | `CMS:read`
- - request: CollectionItem.
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow import CollectionItem, CollectionItemFieldData
- from webflow.client import Webflow
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
- client = Webflow(
- access_token="YOUR_ACCESS_TOKEN",
- )
- client.collections.items.update_item(
- collection_id="collection_id",
- item_id="item_id",
- request=CollectionItem(
- id="42b720ef280c7a7a3be8cabe",
- cms_locale_id="653ad57de882f528b32e810e",
- last_published="2022-11-29T16:22:43.159Z",
- last_updated="2022-11-17T17:19:43.282Z",
- created_on="2022-11-17T17:11:57.148Z",
- is_archived=False,
- is_draft=False,
- field_data=CollectionItemFieldData(
- name="Pan Galactic Gargle Blaster Recipe",
- slug="pan-galactic-gargle-blaster",
- ),
- ),
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- "PATCH",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(CollectionItem, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
- def delete_item_live(
- self, collection_id: str, item_id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> None:
- """
- Delete a live Item from a Collection. The Item will be unpublished from the live site. This endpoint does not currently support bulk deletion. Required scope | `CMS:write`
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ name : typing.Optional[str]
+ Filter by the exact name of the item(s)
- - item_id: str. Unique identifier for an Item
+ slug : typing.Optional[str]
+ Filter by the exact slug of the item
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ last_published : typing.Optional[ItemsListItemsLiveRequestLastPublished]
+ Filter by the last published date of the item(s)
+
+ sort_by : typing.Optional[ItemsListItemsLiveRequestSortBy]
+ Sort results by the provided value
+
+ sort_order : typing.Optional[ItemsListItemsLiveRequestSortOrder]
+ Sorts the results by asc or desc
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ CollectionItemList
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
- client.collections.items.delete_item_live(
- collection_id="collection_id",
- item_id="item_id",
+ client.collections.items.list_items_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ cms_locale_id="cmsLocaleId",
+ offset=1,
+ limit=1,
+ name="name",
+ slug="slug",
+ sort_by="lastPublished",
+ sort_order="asc",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "DELETE",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/live",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.list_items_live(
+ collection_id,
+ cms_locale_id=cms_locale_id,
+ offset=offset,
+ limit=limit,
+ name=name,
+ slug=slug,
+ last_published=last_published,
+ sort_by=sort_by,
+ sort_order=sort_order,
+ request_options=request_options,
+ )
+ return _response.data
- def update_item_live(
+ def create_item_live(
self,
collection_id: str,
- item_id: str,
*,
- request: CollectionItem,
+ request: ItemsCreateItemLiveRequestBody,
+ skip_invalid_files: typing.Optional[bool] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> CollectionItem:
"""
- Update a selected live Item in a Collection. The updates for this Item will be published to the live site. Required scope | `CMS:write`
+ Create item(s) in a collection that will be immediately published to the live site.
+
+
+ To create items across multiple locales, [please use this endpoint.](/data/reference/cms/collection-items/staged-items/create-items)
- Parameters:
- - collection_id: str. Unique identifier for a Collection
- - item_id: str. Unique identifier for an Item
+ Required scope | `CMS:write`
- - request: CollectionItem.
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow import CollectionItem, CollectionItemFieldData
- from webflow.client import Webflow
+ 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.
+
+ Returns
+ -------
+ CollectionItem
+ Request was successful
+
+ Examples
+ --------
+ from webflow import CollectionItem, CollectionItemFieldData, Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
- client.collections.items.update_item_live(
- collection_id="collection_id",
- item_id="item_id",
+ client.collections.items.create_item_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ skip_invalid_files=True,
request=CollectionItem(
- id="42b720ef280c7a7a3be8cabe",
- cms_locale_id="653ad57de882f528b32e810e",
- last_published="2022-11-29T16:22:43.159Z",
- last_updated="2022-11-17T17:19:43.282Z",
- created_on="2022-11-17T17:11:57.148Z",
is_archived=False,
is_draft=False,
field_data=CollectionItemFieldData(
- name="Pan Galactic Gargle Blaster Recipe",
- slug="pan-galactic-gargle-blaster",
+ name="The Hitchhiker's Guide to the Galaxy",
+ slug="hitchhikers-guide-to-the-galaxy",
),
),
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "PATCH",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/live",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(CollectionItem, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.create_item_live(
+ collection_id, request=request, skip_invalid_files=skip_invalid_files, request_options=request_options
+ )
+ return _response.data
- def publish_item(
+ def delete_items_live(
self,
collection_id: str,
*,
- item_ids: typing.Sequence[str],
+ items: typing.Sequence[ItemsDeleteItemsLiveRequestItemsItem],
request_options: typing.Optional[RequestOptions] = None,
- ) -> ItemsPublishItemResponse:
+ ) -> None:
"""
- Publish an item or multiple items. Required scope | `cms:write`
+ Unpublish up to 100 items from the live site and set the `isDraft` property to `true`.
+
+ Items will only be unpublished in the primary locale unless a `cmsLocaleId` is included in the request.
+
+ Required scope | `CMS:write`
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
- - item_ids: typing.Sequence[str].
+ items : typing.Sequence[ItemsDeleteItemsLiveRequestItemsItem]
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ from webflow import Webflow
+ from webflow.resources.collections.resources.items import (
+ ItemsDeleteItemsLiveRequestItemsItem,
+ )
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
- client.collections.items.publish_item(
- collection_id="collection_id",
- item_ids=["itemIds"],
+ client.collections.items.delete_items_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ items=[
+ ItemsDeleteItemsLiveRequestItemsItem(
+ id="580e64008c9a982ac9b8b754",
+ )
+ ],
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"collections/{jsonable_encoder(collection_id)}/items/publish",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder({"itemIds": item_ids})
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder({"itemIds": item_ids}),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(ItemsPublishItemResponse, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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 AsyncItemsClient:
- def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
+ _response = self._raw_client.delete_items_live(collection_id, items=items, request_options=request_options)
+ return _response.data
- async def list_items(
+ def update_items_live(
self,
collection_id: str,
*,
- cms_locale_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- offset: typing.Optional[float] = None,
- limit: typing.Optional[float] = None,
+ skip_invalid_files: typing.Optional[bool] = None,
+ items: typing.Optional[typing.Sequence[CollectionItemWithIdInput]] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> CollectionItemList:
+ ) -> CollectionItemListNoPagination:
"""
- List of all Items within a Collection. Required scope | `CMS:read`
-
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ Update a single published item or multiple published items (up to 100) in a Collection
- - cms_locale_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]]. Unique identifiers for CMS Locales. These UIDs are different from the Site locale identifier and are listed as `cmsLocaleId` in the Sites response. Applicable when using localization.
+ Items will only be updated in the primary locale, unless a `cmsLocaleId` is included in the request.
- - offset: typing.Optional[float]. Offset used for pagination if the results have more than limit records
+ Required scope | `CMS:write`
- - limit: typing.Optional[float]. Maximum number of records to be returned (max limit: 100)
-
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
-
- client = AsyncWebflow(
- access_token="YOUR_ACCESS_TOKEN",
- )
- await client.collections.items.list_items(
- collection_id="collection_id",
- )
- """
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"collections/{jsonable_encoder(collection_id)}/items"
- ),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "cmsLocaleIds": cms_locale_ids,
- "offset": offset,
- "limit": limit,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(CollectionItemList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
- async def create_item(
- self, collection_id: str, *, request: CollectionItem, request_options: typing.Optional[RequestOptions] = None
- ) -> None:
- """
- Create Item in a Collection. To create items across multiple locales, please use this endpoint. Required scope | `CMS:write`
+ 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.
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ items : typing.Optional[typing.Sequence[CollectionItemWithIdInput]]
- - request: CollectionItem.
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow import CollectionItem, CollectionItemFieldData
- from webflow.client import AsyncWebflow
+ Returns
+ -------
+ CollectionItemListNoPagination
+ Request was successful
- client = AsyncWebflow(
- access_token="YOUR_ACCESS_TOKEN",
- )
- await client.collections.items.create_item(
- collection_id="collection_id",
- request=CollectionItem(
- id="42b720ef280c7a7a3be8cabe",
- cms_locale_id="653ad57de882f528b32e810e",
- last_published="2022-11-29T16:22:43.159Z",
- last_updated="2022-11-17T17:19:43.282Z",
- created_on="2022-11-17T17:11:57.148Z",
- is_archived=False,
- is_draft=False,
- field_data=CollectionItemFieldData(
- name="Pan Galactic Gargle Blaster Recipe",
- slug="pan-galactic-gargle-blaster",
- ),
- ),
+ Examples
+ --------
+ from webflow import (
+ CollectionItemWithIdInput,
+ CollectionItemWithIdInputFieldData,
+ Webflow,
)
- """
- _response = await self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"collections/{jsonable_encoder(collection_id)}/items"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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 create_item_live(
- self, collection_id: str, *, request: CollectionItem, request_options: typing.Optional[RequestOptions] = None
- ) -> None:
- """
- Create live Item in a Collection. This Item will be published to the live site. To create items across multiple locales, please use this endpoint. Required scope | `CMS:write`
-
- Parameters:
- - collection_id: str. Unique identifier for a Collection
-
- - request: CollectionItem.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow import CollectionItem, CollectionItemFieldData
- from webflow.client import AsyncWebflow
-
- client = AsyncWebflow(
+ client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.collections.items.create_item_live(
- collection_id="collection_id",
- request=CollectionItem(
- id="42b720ef280c7a7a3be8cabe",
- cms_locale_id="653ad57de882f528b32e810e",
- last_published="2022-11-29T16:22:43.159Z",
- last_updated="2022-11-17T17:19:43.282Z",
- created_on="2022-11-17T17:11:57.148Z",
- is_archived=False,
- is_draft=False,
- field_data=CollectionItemFieldData(
- name="Pan Galactic Gargle Blaster Recipe",
- slug="pan-galactic-gargle-blaster",
+ client.collections.items.update_items_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ skip_invalid_files=True,
+ items=[
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5ea6",
+ cms_locale_id="66f6e966c9e1dc700a857ca5",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="Ne Paniquez Pas",
+ slug="ne-paniquez-pas",
+ ),
),
- ),
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5ea6",
+ cms_locale_id="66f6e966c9e1dc700a857ca4",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="No Entrar en Pánico",
+ slug="no-entrar-en-panico",
+ ),
+ ),
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5eaa",
+ cms_locale_id="66f6e966c9e1dc700a857ca5",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="Au Revoir et Merci pour Tous les Poissons",
+ slug="au-revoir-et-merci",
+ ),
+ ),
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5eaa",
+ cms_locale_id="66f6e966c9e1dc700a857ca4",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="Hasta Luego y Gracias por Todo el Pescado",
+ slug="hasta-luego-y-gracias",
+ ),
+ ),
+ ],
)
"""
- _response = await self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"collections/{jsonable_encoder(collection_id)}/items/live"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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 create_item_for_multiple_locales(
+ _response = self._raw_client.update_items_live(
+ collection_id, skip_invalid_files=skip_invalid_files, items=items, request_options=request_options
+ )
+ return _response.data
+
+ def create_items(
self,
collection_id: str,
*,
- id: str,
+ field_data: CreateBulkCollectionItemRequestBodyFieldData,
+ skip_invalid_files: typing.Optional[bool] = None,
cms_locale_ids: typing.Optional[typing.Sequence[str]] = OMIT,
- last_published: typing.Optional[str] = OMIT,
- last_updated: typing.Optional[str] = OMIT,
- created_on: typing.Optional[str] = OMIT,
is_archived: typing.Optional[bool] = OMIT,
is_draft: typing.Optional[bool] = OMIT,
- field_data: typing.Optional[BulkCollectionItemFieldData] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> None:
+ ) -> BulkCollectionItem:
"""
- Create single Item in a Collection with multiple corresponding locales. Required scope | `CMS:write`
+ Create an item or multiple items in a CMS Collection across multiple corresponding locales.
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+
+ - This endpoint can create up to 100 items in a request.
+ - If the `cmsLocaleIds` parameter is not included in the request, an item will only be created in the primary locale.
+
- - id: str. Unique identifier for the Item
+ Required scope | `CMS:write`
- - cms_locale_ids: typing.Optional[typing.Sequence[str]]. Array of identifiers for the locales where the item will be created
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
- - last_published: typing.Optional[str]. The date the item was last published
+ field_data : CreateBulkCollectionItemRequestBodyFieldData
- - last_updated: typing.Optional[str]. The date the item was last updated
+ 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.
- - created_on: typing.Optional[str]. The date the item was created
+ cms_locale_ids : typing.Optional[typing.Sequence[str]]
+ Array of identifiers for the locales where the item will be created
- - is_archived: typing.Optional[bool]. Boolean determining if the Item is set to archived
+ is_archived : typing.Optional[bool]
+ Indicates whether the item is archived.
- - is_draft: typing.Optional[bool]. Boolean determining if the Item is set to draft
+ is_draft : typing.Optional[bool]
+ Indicates whether the item is in draft state.
- - field_data: typing.Optional[BulkCollectionItemFieldData].
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
- from webflow.resources.collections import BulkCollectionItemFieldData
+ Returns
+ -------
+ BulkCollectionItem
+ Request was successful
- client = AsyncWebflow(
+ Examples
+ --------
+ from webflow import Webflow
+ from webflow.resources.collections.resources.items import SingleCmsItem
+
+ client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.collections.items.create_item_for_multiple_locales(
- collection_id="collection_id",
- id="580e64008c9a982ac9b8b754",
- last_published="2023-03-17T18:47:35.560Z",
- last_updated="2023-03-17T18:47:35.560Z",
- created_on="2023-03-17T18:47:35.560Z",
- field_data=BulkCollectionItemFieldData(
- name="My new item",
- slug="my-new-item",
+ client.collections.items.create_items(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ skip_invalid_files=True,
+ cms_locale_ids=[
+ "66f6e966c9e1dc700a857ca3",
+ "66f6e966c9e1dc700a857ca4",
+ "66f6e966c9e1dc700a857ca5",
+ ],
+ is_archived=False,
+ is_draft=False,
+ field_data=SingleCmsItem(
+ name="Don’t Panic",
+ slug="dont-panic",
),
)
"""
- _request: typing.Dict[str, typing.Any] = {"id": id}
- if cms_locale_ids is not OMIT:
- _request["cmsLocaleIds"] = cms_locale_ids
- if last_published is not OMIT:
- _request["lastPublished"] = last_published
- if last_updated is not OMIT:
- _request["lastUpdated"] = last_updated
- if created_on is not OMIT:
- _request["createdOn"] = created_on
- if is_archived is not OMIT:
- _request["isArchived"] = is_archived
- if is_draft is not OMIT:
- _request["isDraft"] = is_draft
- if field_data is not OMIT:
- _request["fieldData"] = field_data
- _response = await self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"collections/{jsonable_encoder(collection_id)}/items/bulk"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.create_items(
+ collection_id,
+ field_data=field_data,
+ skip_invalid_files=skip_invalid_files,
+ cms_locale_ids=cms_locale_ids,
+ is_archived=is_archived,
+ is_draft=is_draft,
+ request_options=request_options,
+ )
+ return _response.data
- async def get_item(
+ def get_item(
self,
collection_id: str,
item_id: str,
@@ -1226,461 +718,1701 @@ async def get_item(
request_options: typing.Optional[RequestOptions] = None,
) -> CollectionItem:
"""
- Get details of a selected Collection Item. Required scope | `CMS:read`
+ Get details of a selected Collection Item.
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ Required scope | `CMS:read`
- - item_id: str. Unique identifier for an Item
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
- - cms_locale_id: typing.Optional[str]. Unique identifier for a CMS Locale. These UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. Applicable when using localization.
+ item_id : str
+ Unique identifier for an Item
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
- client = AsyncWebflow(
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ CollectionItem
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
+
+ client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.collections.items.get_item(
- collection_id="collection_id",
- item_id="item_id",
+ client.collections.items.get_item(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ item_id="580e64008c9a982ac9b8b754",
+ cms_locale_id="cmsLocaleId",
+ )
+ """
+ _response = self._raw_client.get_item(
+ collection_id, item_id, cms_locale_id=cms_locale_id, request_options=request_options
+ )
+ return _response.data
+
+ def delete_item(
+ self,
+ collection_id: str,
+ item_id: str,
+ *,
+ cms_locale_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> None:
+ """
+ Delete an item from a collection.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ item_id : str
+ Unique identifier for an Item
+
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ from webflow import Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.collections.items.delete_item(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ item_id="580e64008c9a982ac9b8b754",
+ cms_locale_id="cmsLocaleId",
+ )
+ """
+ _response = self._raw_client.delete_item(
+ collection_id, item_id, cms_locale_id=cms_locale_id, request_options=request_options
+ )
+ return _response.data
+
+ def update_item(
+ self,
+ 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,
+ last_updated: typing.Optional[str] = OMIT,
+ created_on: typing.Optional[str] = OMIT,
+ is_archived: typing.Optional[bool] = OMIT,
+ is_draft: typing.Optional[bool] = OMIT,
+ field_data: typing.Optional[CollectionItemPatchSingleFieldData] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> CollectionItem:
+ """
+ Update a selected Item in a Collection.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ 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
+
+ cms_locale_id : typing.Optional[str]
+ Identifier for the locale of the CMS item
+
+ last_published : typing.Optional[str]
+ The date the item was last published
+
+ last_updated : typing.Optional[str]
+ The date the item was last updated
+
+ created_on : typing.Optional[str]
+ The date the item was created
+
+ is_archived : typing.Optional[bool]
+ Boolean determining if the Item is set to archived
+
+ is_draft : typing.Optional[bool]
+ Boolean determining if the Item is set to draft
+
+ field_data : typing.Optional[CollectionItemPatchSingleFieldData]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ CollectionItem
+ Request was successful
+
+ Examples
+ --------
+ from webflow import CollectionItemPatchSingleFieldData, Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.collections.items.update_item(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ item_id="580e64008c9a982ac9b8b754",
+ skip_invalid_files=True,
+ is_archived=False,
+ is_draft=False,
+ field_data=CollectionItemPatchSingleFieldData(
+ name="The Hitchhiker's Guide to the Galaxy",
+ slug="hitchhikers-guide-to-the-galaxy",
+ ),
+ )
+ """
+ _response = self._raw_client.update_item(
+ collection_id,
+ item_id,
+ skip_invalid_files=skip_invalid_files,
+ id=id,
+ cms_locale_id=cms_locale_id,
+ last_published=last_published,
+ last_updated=last_updated,
+ created_on=created_on,
+ is_archived=is_archived,
+ is_draft=is_draft,
+ field_data=field_data,
+ request_options=request_options,
+ )
+ return _response.data
+
+ def get_item_live(
+ self,
+ collection_id: str,
+ item_id: str,
+ *,
+ cms_locale_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> CollectionItem:
+ """
+ Get details of a selected Collection live Item.
+
+
+ Serving data to applications in real-time? Use the Content Delivery API at `api-cdn.webflow.com` for better performance. The CDN-backed endpoint is optimized for high-volume reads, while the Data API is designed for writes and management operations.
+
+
+ Required scope | `CMS:read`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ item_id : str
+ Unique identifier for an Item
+
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ CollectionItem
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.collections.items.get_item_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ item_id="580e64008c9a982ac9b8b754",
+ cms_locale_id="cmsLocaleId",
+ )
+ """
+ _response = self._raw_client.get_item_live(
+ collection_id, item_id, cms_locale_id=cms_locale_id, request_options=request_options
+ )
+ return _response.data
+
+ def delete_item_live(
+ self,
+ collection_id: str,
+ item_id: str,
+ *,
+ cms_locale_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> None:
+ """
+ Unpublish a live item from the site and set the `isDraft` property to `true`.
+
+ For bulk unpublishing, please use [this endpoint.](/data/v2.0.0/reference/cms/collection-items/live-items/delete-items-live)
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ item_id : str
+ Unique identifier for an Item
+
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ from webflow import Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.collections.items.delete_item_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ item_id="580e64008c9a982ac9b8b754",
+ cms_locale_id="cmsLocaleId",
+ )
+ """
+ _response = self._raw_client.delete_item_live(
+ collection_id, item_id, cms_locale_id=cms_locale_id, request_options=request_options
+ )
+ return _response.data
+
+ def update_item_live(
+ self,
+ 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,
+ last_updated: typing.Optional[str] = OMIT,
+ created_on: typing.Optional[str] = OMIT,
+ is_archived: typing.Optional[bool] = OMIT,
+ is_draft: typing.Optional[bool] = OMIT,
+ field_data: typing.Optional[CollectionItemPatchSingleFieldData] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> CollectionItem:
+ """
+ Update a selected live Item in a Collection. The updates for this Item will be published to the live site.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ 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
+
+ cms_locale_id : typing.Optional[str]
+ Identifier for the locale of the CMS item
+
+ last_published : typing.Optional[str]
+ The date the item was last published
+
+ last_updated : typing.Optional[str]
+ The date the item was last updated
+
+ created_on : typing.Optional[str]
+ The date the item was created
+
+ is_archived : typing.Optional[bool]
+ Boolean determining if the Item is set to archived
+
+ is_draft : typing.Optional[bool]
+ Boolean determining if the Item is set to draft
+
+ field_data : typing.Optional[CollectionItemPatchSingleFieldData]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ CollectionItem
+ Request was successful
+
+ Examples
+ --------
+ from webflow import CollectionItemPatchSingleFieldData, Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.collections.items.update_item_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ item_id="580e64008c9a982ac9b8b754",
+ skip_invalid_files=True,
+ is_archived=False,
+ is_draft=False,
+ field_data=CollectionItemPatchSingleFieldData(
+ name="The Hitchhiker's Guide to the Galaxy",
+ slug="hitchhikers-guide-to-the-galaxy",
+ ),
+ )
+ """
+ _response = self._raw_client.update_item_live(
+ collection_id,
+ item_id,
+ skip_invalid_files=skip_invalid_files,
+ id=id,
+ cms_locale_id=cms_locale_id,
+ last_published=last_published,
+ last_updated=last_updated,
+ created_on=created_on,
+ is_archived=is_archived,
+ is_draft=is_draft,
+ field_data=field_data,
+ request_options=request_options,
+ )
+ return _response.data
+
+ def publish_item(
+ self,
+ collection_id: str,
+ *,
+ request: ItemsPublishItemRequest,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ItemsPublishItemResponse:
+ """
+ Publish an item or multiple items.
+
+ Required scope | `cms:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ request : ItemsPublishItemRequest
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ItemsPublishItemResponse
+ Request was successful
+
+ 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",
+ request=ItemIDs(
+ item_ids=[
+ "643fd856d66b6528195ee2ca",
+ "643fd856d66b6528195ee2cb",
+ "643fd856d66b6528195ee2cc",
+ ],
+ ),
+ )
+ """
+ _response = self._raw_client.publish_item(collection_id, request=request, request_options=request_options)
+ return _response.data
+
+
+class AsyncItemsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._raw_client = AsyncRawItemsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawItemsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawItemsClient
+ """
+ return self._raw_client
+
+ async def list_items(
+ self,
+ collection_id: str,
+ *,
+ cms_locale_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ name: typing.Optional[str] = None,
+ slug: typing.Optional[str] = None,
+ last_published: typing.Optional[ItemsListItemsRequestLastPublished] = None,
+ sort_by: typing.Optional[ItemsListItemsRequestSortBy] = None,
+ sort_order: typing.Optional[ItemsListItemsRequestSortOrder] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> CollectionItemList:
+ """
+ List of all Items within a Collection.
+
+ Required scope | `CMS:read`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ name : typing.Optional[str]
+ Filter by the exact name of the item(s)
+
+ slug : typing.Optional[str]
+ Filter by the exact slug of the item
+
+ last_published : typing.Optional[ItemsListItemsRequestLastPublished]
+ Filter by the last published date of the item(s)
+
+ sort_by : typing.Optional[ItemsListItemsRequestSortBy]
+ Sort results by the provided value
+
+ sort_order : typing.Optional[ItemsListItemsRequestSortOrder]
+ Sorts the results by asc or desc
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ CollectionItemList
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.collections.items.list_items(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ cms_locale_id="cmsLocaleId",
+ offset=1,
+ limit=1,
+ name="name",
+ slug="slug",
+ sort_by="lastPublished",
+ sort_order="asc",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.list_items(
+ collection_id,
+ cms_locale_id=cms_locale_id,
+ offset=offset,
+ limit=limit,
+ name=name,
+ slug=slug,
+ last_published=last_published,
+ sort_by=sort_by,
+ sort_order=sort_order,
+ request_options=request_options,
+ )
+ return _response.data
+
+ async def create_item(
+ self,
+ collection_id: str,
+ *,
+ 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.](/data/reference/cms/collection-items/staged-items/create-items)
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ 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.
+
+ Returns
+ -------
+ CollectionItem
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import (
+ AsyncWebflow,
+ CollectionItemPostSingle,
+ CollectionItemPostSingleFieldData,
+ )
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.collections.items.create_item(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ skip_invalid_files=True,
+ request=CollectionItemPostSingle(
+ is_archived=False,
+ is_draft=False,
+ field_data=CollectionItemPostSingleFieldData(
+ name="The Hitchhiker's Guide to the Galaxy",
+ slug="hitchhikers-guide-to-the-galaxy",
+ ),
+ ),
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.create_item(
+ collection_id, request=request, skip_invalid_files=skip_invalid_files, request_options=request_options
+ )
+ return _response.data
+
+ async def delete_items(
+ self,
+ collection_id: str,
+ *,
+ items: typing.Sequence[ItemsDeleteItemsRequestItemsItem],
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> None:
+ """
+ Delete Items from a Collection.
+
+ Items will only be deleted in the primary locale unless a `cmsLocaleId` is included in the request.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ items : typing.Sequence[ItemsDeleteItemsRequestItemsItem]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+ from webflow.resources.collections.resources.items import (
+ ItemsDeleteItemsRequestItemsItem,
+ )
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.collections.items.delete_items(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ items=[
+ ItemsDeleteItemsRequestItemsItem(
+ id="580e64008c9a982ac9b8b754",
+ )
+ ],
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.delete_items(collection_id, items=items, request_options=request_options)
+ return _response.data
+
+ 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,
+ ) -> ItemsUpdateItemsResponse:
+ """
+ Update a single item or multiple items in a Collection.
+
+ 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`
+
+ Parameters
+ ----------
+ 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]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ItemsUpdateItemsResponse
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import (
+ AsyncWebflow,
+ CollectionItemWithIdInput,
+ CollectionItemWithIdInputFieldData,
+ )
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.collections.items.update_items(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ skip_invalid_files=True,
+ items=[
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5ea6",
+ cms_locale_id="66f6e966c9e1dc700a857ca5",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="Ne Paniquez Pas",
+ slug="ne-paniquez-pas",
+ ),
+ ),
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5ea6",
+ cms_locale_id="66f6e966c9e1dc700a857ca4",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="No Entrar en Pánico",
+ slug="no-entrar-en-panico",
+ ),
+ ),
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5eaa",
+ cms_locale_id="66f6e966c9e1dc700a857ca5",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="Au Revoir et Merci pour Tous les Poissons",
+ slug="au-revoir-et-merci",
+ ),
+ ),
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5eaa",
+ cms_locale_id="66f6e966c9e1dc700a857ca4",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="Hasta Luego y Gracias por Todo el Pescado",
+ slug="hasta-luego-y-gracias",
+ ),
+ ),
+ ],
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.update_items(
+ collection_id, skip_invalid_files=skip_invalid_files, items=items, request_options=request_options
+ )
+ return _response.data
+
+ async def list_items_live(
+ self,
+ collection_id: str,
+ *,
+ cms_locale_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ name: typing.Optional[str] = None,
+ slug: typing.Optional[str] = None,
+ last_published: typing.Optional[ItemsListItemsLiveRequestLastPublished] = None,
+ sort_by: typing.Optional[ItemsListItemsLiveRequestSortBy] = None,
+ sort_order: typing.Optional[ItemsListItemsLiveRequestSortOrder] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> CollectionItemList:
+ """
+ List all published items in a collection.
+
+
+ Serving data to applications in real-time? Use the Content Delivery API at `api-cdn.webflow.com` for better performance. The CDN-backed endpoint is optimized for high-volume reads, while the Data API is designed for writes and management operations.
+
+
+ Required scope | `CMS:read`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ name : typing.Optional[str]
+ Filter by the exact name of the item(s)
+
+ slug : typing.Optional[str]
+ Filter by the exact slug of the item
+
+ last_published : typing.Optional[ItemsListItemsLiveRequestLastPublished]
+ Filter by the last published date of the item(s)
+
+ sort_by : typing.Optional[ItemsListItemsLiveRequestSortBy]
+ Sort results by the provided value
+
+ sort_order : typing.Optional[ItemsListItemsLiveRequestSortOrder]
+ Sorts the results by asc or desc
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ CollectionItemList
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.collections.items.list_items_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ cms_locale_id="cmsLocaleId",
+ offset=1,
+ limit=1,
+ name="name",
+ slug="slug",
+ sort_by="lastPublished",
+ sort_order="asc",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.list_items_live(
+ collection_id,
+ cms_locale_id=cms_locale_id,
+ offset=offset,
+ limit=limit,
+ name=name,
+ slug=slug,
+ last_published=last_published,
+ sort_by=sort_by,
+ sort_order=sort_order,
+ request_options=request_options,
+ )
+ return _response.data
+
+ async def create_item_live(
+ self,
+ collection_id: str,
+ *,
+ request: ItemsCreateItemLiveRequestBody,
+ skip_invalid_files: typing.Optional[bool] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> CollectionItem:
+ """
+ Create item(s) in a collection that will be immediately published to the live site.
+
+
+ To create items across multiple locales, [please use this endpoint.](/data/reference/cms/collection-items/staged-items/create-items)
+
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ 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.
+
+ Returns
+ -------
+ CollectionItem
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow, CollectionItem, CollectionItemFieldData
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.collections.items.create_item_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ skip_invalid_files=True,
+ request=CollectionItem(
+ is_archived=False,
+ is_draft=False,
+ field_data=CollectionItemFieldData(
+ name="The Hitchhiker's Guide to the Galaxy",
+ slug="hitchhikers-guide-to-the-galaxy",
+ ),
+ ),
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.create_item_live(
+ collection_id, request=request, skip_invalid_files=skip_invalid_files, request_options=request_options
+ )
+ return _response.data
+
+ async def delete_items_live(
+ self,
+ collection_id: str,
+ *,
+ items: typing.Sequence[ItemsDeleteItemsLiveRequestItemsItem],
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> None:
+ """
+ Unpublish up to 100 items from the live site and set the `isDraft` property to `true`.
+
+ Items will only be unpublished in the primary locale unless a `cmsLocaleId` is included in the request.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ items : typing.Sequence[ItemsDeleteItemsLiveRequestItemsItem]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+ from webflow.resources.collections.resources.items import (
+ ItemsDeleteItemsLiveRequestItemsItem,
+ )
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
)
+
+
+ async def main() -> None:
+ await client.collections.items.delete_items_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ items=[
+ ItemsDeleteItemsLiveRequestItemsItem(
+ id="580e64008c9a982ac9b8b754",
+ )
+ ],
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}",
- ),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "cmsLocaleId": cms_locale_id,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
+ _response = await self._raw_client.delete_items_live(
+ collection_id, items=items, request_options=request_options
+ )
+ return _response.data
+
+ 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 published item or multiple published items (up to 100) in a Collection
+
+ Items will only be updated in the primary locale, unless a `cmsLocaleId` is included in the request.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ 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]
+ Request-specific configuration.
+
+ Returns
+ -------
+ CollectionItemListNoPagination
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import (
+ AsyncWebflow,
+ CollectionItemWithIdInput,
+ CollectionItemWithIdInputFieldData,
+ )
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.collections.items.update_items_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ skip_invalid_files=True,
+ items=[
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5ea6",
+ cms_locale_id="66f6e966c9e1dc700a857ca5",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="Ne Paniquez Pas",
+ slug="ne-paniquez-pas",
),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(CollectionItem, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ ),
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5ea6",
+ cms_locale_id="66f6e966c9e1dc700a857ca4",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="No Entrar en Pánico",
+ slug="no-entrar-en-panico",
+ ),
+ ),
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5eaa",
+ cms_locale_id="66f6e966c9e1dc700a857ca5",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="Au Revoir et Merci pour Tous les Poissons",
+ slug="au-revoir-et-merci",
+ ),
+ ),
+ CollectionItemWithIdInput(
+ id="66f6ed9576ddacf3149d5eaa",
+ cms_locale_id="66f6e966c9e1dc700a857ca4",
+ field_data=CollectionItemWithIdInputFieldData(
+ name="Hasta Luego y Gracias por Todo el Pescado",
+ slug="hasta-luego-y-gracias",
+ ),
+ ),
+ ],
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.update_items_live(
+ collection_id, skip_invalid_files=skip_invalid_files, items=items, request_options=request_options
+ )
+ return _response.data
+
+ async def create_items(
+ self,
+ 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,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> BulkCollectionItem:
+ """
+ Create an item or multiple items in a CMS Collection across multiple corresponding locales.
+
+
+ - This endpoint can create up to 100 items in a request.
+ - If the `cmsLocaleIds` parameter is not included in the request, an item will only be created in the primary locale.
+
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ 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
+
+ is_archived : typing.Optional[bool]
+ Indicates whether the item is archived.
+
+ is_draft : typing.Optional[bool]
+ Indicates whether the item is in draft state.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ BulkCollectionItem
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+ from webflow.resources.collections.resources.items import SingleCmsItem
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.collections.items.create_items(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ skip_invalid_files=True,
+ cms_locale_ids=[
+ "66f6e966c9e1dc700a857ca3",
+ "66f6e966c9e1dc700a857ca4",
+ "66f6e966c9e1dc700a857ca5",
+ ],
+ is_archived=False,
+ is_draft=False,
+ field_data=SingleCmsItem(
+ name="Don’t Panic",
+ slug="dont-panic",
+ ),
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.create_items(
+ collection_id,
+ field_data=field_data,
+ skip_invalid_files=skip_invalid_files,
+ cms_locale_ids=cms_locale_ids,
+ is_archived=is_archived,
+ is_draft=is_draft,
+ request_options=request_options,
+ )
+ return _response.data
+
+ async def get_item(
+ self,
+ collection_id: str,
+ item_id: str,
+ *,
+ cms_locale_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> CollectionItem:
+ """
+ Get details of a selected Collection Item.
+
+ Required scope | `CMS:read`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ item_id : str
+ Unique identifier for an Item
+
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ CollectionItem
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.collections.items.get_item(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ item_id="580e64008c9a982ac9b8b754",
+ cms_locale_id="cmsLocaleId",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.get_item(
+ collection_id, item_id, cms_locale_id=cms_locale_id, request_options=request_options
+ )
+ return _response.data
async def delete_item(
self,
collection_id: str,
item_id: str,
*,
- cms_locale_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
+ cms_locale_id: typing.Optional[str] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> None:
"""
- Delete an Item from a Collection. This endpoint does not currently support bulk deletion. Required scope | `CMS:write`
+ Delete an item from a collection.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ item_id : str
+ Unique identifier for an Item
- - item_id: str. Unique identifier for an Item
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
- - cms_locale_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]]. Unique identifiers for CMS Locales. These UIDs are different from the Site locale identifier and are listed as `cmsLocaleId` in the Sites response. Applicable when using localization.
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.collections.items.delete_item(
- collection_id="collection_id",
- item_id="item_id",
- )
+
+
+ async def main() -> None:
+ await client.collections.items.delete_item(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ item_id="580e64008c9a982ac9b8b754",
+ cms_locale_id="cmsLocaleId",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "DELETE",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}",
- ),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "cmsLocaleIds": cms_locale_ids,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.delete_item(
+ collection_id, item_id, cms_locale_id=cms_locale_id, request_options=request_options
+ )
+ return _response.data
async def update_item(
self,
collection_id: str,
item_id: str,
*,
- request: CollectionItem,
+ 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,
+ last_updated: typing.Optional[str] = OMIT,
+ created_on: typing.Optional[str] = OMIT,
+ is_archived: typing.Optional[bool] = OMIT,
+ is_draft: typing.Optional[bool] = OMIT,
+ field_data: typing.Optional[CollectionItemPatchSingleFieldData] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
) -> CollectionItem:
"""
- Update a selected Item in a Collection. Required scope | `CMS:write`
+ Update a selected Item in a Collection.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ 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
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ cms_locale_id : typing.Optional[str]
+ Identifier for the locale of the CMS item
- - item_id: str. Unique identifier for an Item
+ last_published : typing.Optional[str]
+ The date the item was last published
- - request: CollectionItem.
+ last_updated : typing.Optional[str]
+ The date the item was last updated
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow import CollectionItem, CollectionItemFieldData
- from webflow.client import AsyncWebflow
+ created_on : typing.Optional[str]
+ The date the item was created
+
+ is_archived : typing.Optional[bool]
+ Boolean determining if the Item is set to archived
+
+ is_draft : typing.Optional[bool]
+ Boolean determining if the Item is set to draft
+
+ field_data : typing.Optional[CollectionItemPatchSingleFieldData]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ CollectionItem
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow, CollectionItemPatchSingleFieldData
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.collections.items.update_item(
- collection_id="collection_id",
- item_id="item_id",
- request=CollectionItem(
- id="42b720ef280c7a7a3be8cabe",
- cms_locale_id="653ad57de882f528b32e810e",
- last_published="2022-11-29T16:22:43.159Z",
- last_updated="2022-11-17T17:19:43.282Z",
- created_on="2022-11-17T17:11:57.148Z",
+
+
+ async def main() -> None:
+ await client.collections.items.update_item(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ item_id="580e64008c9a982ac9b8b754",
+ skip_invalid_files=True,
is_archived=False,
is_draft=False,
- field_data=CollectionItemFieldData(
- name="Pan Galactic Gargle Blaster Recipe",
- slug="pan-galactic-gargle-blaster",
+ field_data=CollectionItemPatchSingleFieldData(
+ name="The Hitchhiker's Guide to the Galaxy",
+ slug="hitchhikers-guide-to-the-galaxy",
),
- ),
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.update_item(
+ collection_id,
+ item_id,
+ skip_invalid_files=skip_invalid_files,
+ id=id,
+ cms_locale_id=cms_locale_id,
+ last_published=last_published,
+ last_updated=last_updated,
+ created_on=created_on,
+ is_archived=is_archived,
+ is_draft=is_draft,
+ field_data=field_data,
+ request_options=request_options,
+ )
+ return _response.data
+
+ async def get_item_live(
+ self,
+ collection_id: str,
+ item_id: str,
+ *,
+ cms_locale_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> CollectionItem:
+ """
+ Get details of a selected Collection live Item.
+
+
+ Serving data to applications in real-time? Use the Content Delivery API at `api-cdn.webflow.com` for better performance. The CDN-backed endpoint is optimized for high-volume reads, while the Data API is designed for writes and management operations.
+
+
+ Required scope | `CMS:read`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ item_id : str
+ Unique identifier for an Item
+
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ CollectionItem
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
)
+
+
+ async def main() -> None:
+ await client.collections.items.get_item_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ item_id="580e64008c9a982ac9b8b754",
+ cms_locale_id="cmsLocaleId",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "PATCH",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(CollectionItem, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.get_item_live(
+ collection_id, item_id, cms_locale_id=cms_locale_id, request_options=request_options
+ )
+ return _response.data
async def delete_item_live(
- self, collection_id: str, item_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ self,
+ collection_id: str,
+ item_id: str,
+ *,
+ cms_locale_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
) -> None:
"""
- Delete a live Item from a Collection. The Item will be unpublished from the live site. This endpoint does not currently support bulk deletion. Required scope | `CMS:write`
+ Unpublish a live item from the site and set the `isDraft` property to `true`.
+
+ For bulk unpublishing, please use [this endpoint.](/data/v2.0.0/reference/cms/collection-items/live-items/delete-items-live)
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ item_id : str
+ Unique identifier for an Item
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
- - item_id: str. Unique identifier for an Item
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.collections.items.delete_item_live(
- collection_id="collection_id",
- item_id="item_id",
- )
+
+
+ async def main() -> None:
+ await client.collections.items.delete_item_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ item_id="580e64008c9a982ac9b8b754",
+ cms_locale_id="cmsLocaleId",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "DELETE",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/live",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.delete_item_live(
+ collection_id, item_id, cms_locale_id=cms_locale_id, request_options=request_options
+ )
+ return _response.data
async def update_item_live(
self,
collection_id: str,
item_id: str,
*,
- request: CollectionItem,
+ 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,
+ last_updated: typing.Optional[str] = OMIT,
+ created_on: typing.Optional[str] = OMIT,
+ is_archived: typing.Optional[bool] = OMIT,
+ is_draft: typing.Optional[bool] = OMIT,
+ field_data: typing.Optional[CollectionItemPatchSingleFieldData] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
) -> CollectionItem:
"""
- Update a selected live Item in a Collection. The updates for this Item will be published to the live site. Required scope | `CMS:write`
+ Update a selected live Item in a Collection. The updates for this Item will be published to the live site.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ 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
+
+ cms_locale_id : typing.Optional[str]
+ Identifier for the locale of the CMS item
+
+ last_published : typing.Optional[str]
+ The date the item was last published
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ last_updated : typing.Optional[str]
+ The date the item was last updated
- - item_id: str. Unique identifier for an Item
+ created_on : typing.Optional[str]
+ The date the item was created
- - request: CollectionItem.
+ is_archived : typing.Optional[bool]
+ Boolean determining if the Item is set to archived
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow import CollectionItem, CollectionItemFieldData
- from webflow.client import AsyncWebflow
+ is_draft : typing.Optional[bool]
+ Boolean determining if the Item is set to draft
+
+ field_data : typing.Optional[CollectionItemPatchSingleFieldData]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ CollectionItem
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow, CollectionItemPatchSingleFieldData
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.collections.items.update_item_live(
- collection_id="collection_id",
- item_id="item_id",
- request=CollectionItem(
- id="42b720ef280c7a7a3be8cabe",
- cms_locale_id="653ad57de882f528b32e810e",
- last_published="2022-11-29T16:22:43.159Z",
- last_updated="2022-11-17T17:19:43.282Z",
- created_on="2022-11-17T17:11:57.148Z",
+
+
+ async def main() -> None:
+ await client.collections.items.update_item_live(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ item_id="580e64008c9a982ac9b8b754",
+ skip_invalid_files=True,
is_archived=False,
is_draft=False,
- field_data=CollectionItemFieldData(
- name="Pan Galactic Gargle Blaster Recipe",
- slug="pan-galactic-gargle-blaster",
+ field_data=CollectionItemPatchSingleFieldData(
+ name="The Hitchhiker's Guide to the Galaxy",
+ slug="hitchhikers-guide-to-the-galaxy",
),
- ),
- )
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "PATCH",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/live",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(CollectionItem, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.update_item_live(
+ collection_id,
+ item_id,
+ skip_invalid_files=skip_invalid_files,
+ id=id,
+ cms_locale_id=cms_locale_id,
+ last_published=last_published,
+ last_updated=last_updated,
+ created_on=created_on,
+ is_archived=is_archived,
+ is_draft=is_draft,
+ field_data=field_data,
+ request_options=request_options,
+ )
+ return _response.data
async def publish_item(
self,
collection_id: str,
*,
- item_ids: typing.Sequence[str],
+ request: ItemsPublishItemRequest,
request_options: typing.Optional[RequestOptions] = None,
) -> ItemsPublishItemResponse:
"""
- Publish an item or multiple items. Required scope | `cms:write`
+ Publish an item or multiple items.
+
+ Required scope | `cms:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ request : ItemsPublishItemRequest
- - item_ids: typing.Sequence[str].
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Returns
+ -------
+ ItemsPublishItemResponse
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+ from webflow.resources.collections.resources.items import ItemIDs
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.collections.items.publish_item(
- collection_id="collection_id",
- item_ids=["itemIds"],
- )
+
+
+ async def main() -> None:
+ await client.collections.items.publish_item(
+ collection_id="580e63fc8c9a982ac9b8b745",
+ request=ItemIDs(
+ item_ids=[
+ "643fd856d66b6528195ee2ca",
+ "643fd856d66b6528195ee2cb",
+ "643fd856d66b6528195ee2cc",
+ ],
+ ),
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"collections/{jsonable_encoder(collection_id)}/items/publish",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder({"itemIds": item_ids})
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder({"itemIds": item_ids}),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(ItemsPublishItemResponse, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.publish_item(collection_id, request=request, request_options=request_options)
+ return _response.data
diff --git a/src/webflow/resources/collections/resources/items/raw_client.py b/src/webflow/resources/collections/resources/items/raw_client.py
new file mode 100644
index 0000000..010bbfd
--- /dev/null
+++ b/src/webflow/resources/collections/resources/items/raw_client.py
@@ -0,0 +1,4246 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from .....core.api_error import ApiError
+from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .....core.http_response import AsyncHttpResponse, HttpResponse
+from .....core.jsonable_encoder import jsonable_encoder
+from .....core.parse_error import ParsingError
+from .....core.pydantic_utilities import parse_obj_as
+from .....core.request_options import RequestOptions
+from .....core.serialization import convert_and_respect_annotation_metadata
+from .....errors.bad_request_error import BadRequestError
+from .....errors.conflict_error import ConflictError
+from .....errors.internal_server_error import InternalServerError
+from .....errors.not_found_error import NotFoundError
+from .....errors.too_many_requests_error import TooManyRequestsError
+from .....errors.unauthorized_error import UnauthorizedError
+from .....types.bulk_collection_item import BulkCollectionItem
+from .....types.collection_item import CollectionItem
+from .....types.collection_item_list import CollectionItemList
+from .....types.collection_item_list_no_pagination import CollectionItemListNoPagination
+from .....types.collection_item_patch_single_field_data import CollectionItemPatchSingleFieldData
+from .....types.collection_item_with_id_input import CollectionItemWithIdInput
+from .....types.error import Error
+from .....types.items_list_items_live_request_last_published import ItemsListItemsLiveRequestLastPublished
+from .....types.items_list_items_request_last_published import ItemsListItemsRequestLastPublished
+from .types.create_bulk_collection_item_request_body_field_data import CreateBulkCollectionItemRequestBodyFieldData
+from .types.items_create_item_live_request_body import ItemsCreateItemLiveRequestBody
+from .types.items_create_item_request_body import ItemsCreateItemRequestBody
+from .types.items_delete_items_live_request_items_item import ItemsDeleteItemsLiveRequestItemsItem
+from .types.items_delete_items_request_items_item import ItemsDeleteItemsRequestItemsItem
+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_list_items_request_sort_by import ItemsListItemsRequestSortBy
+from .types.items_list_items_request_sort_order import ItemsListItemsRequestSortOrder
+from .types.items_publish_item_request import ItemsPublishItemRequest
+from .types.items_publish_item_response import ItemsPublishItemResponse
+from .types.items_update_items_response import ItemsUpdateItemsResponse
+from pydantic import ValidationError
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RawItemsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def list_items(
+ self,
+ collection_id: str,
+ *,
+ cms_locale_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ name: typing.Optional[str] = None,
+ slug: typing.Optional[str] = None,
+ last_published: typing.Optional[ItemsListItemsRequestLastPublished] = None,
+ sort_by: typing.Optional[ItemsListItemsRequestSortBy] = None,
+ sort_order: typing.Optional[ItemsListItemsRequestSortOrder] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[CollectionItemList]:
+ """
+ List of all Items within a Collection.
+
+ Required scope | `CMS:read`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ name : typing.Optional[str]
+ Filter by the exact name of the item(s)
+
+ slug : typing.Optional[str]
+ Filter by the exact slug of the item
+
+ last_published : typing.Optional[ItemsListItemsRequestLastPublished]
+ Filter by the last published date of the item(s)
+
+ sort_by : typing.Optional[ItemsListItemsRequestSortBy]
+ Sort results by the provided value
+
+ sort_order : typing.Optional[ItemsListItemsRequestSortOrder]
+ Sorts the results by asc or desc
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[CollectionItemList]
+ Request was successful
+ """
+ _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,
+ "offset": offset,
+ "limit": limit,
+ "name": name,
+ "slug": slug,
+ "lastPublished": convert_and_respect_annotation_metadata(
+ object_=last_published, annotation=ItemsListItemsRequestLastPublished, direction="write"
+ ),
+ "sortBy": sort_by,
+ "sortOrder": sort_order,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CollectionItemList,
+ parse_obj_as(
+ type_=CollectionItemList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def create_item(
+ self,
+ collection_id: str,
+ *,
+ request: ItemsCreateItemRequestBody,
+ skip_invalid_files: typing.Optional[bool] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[CollectionItem]:
+ """
+ Create Item(s) in a Collection.
+
+
+ To create items across multiple locales, please use [this endpoint.](/data/reference/cms/collection-items/staged-items/create-items)
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ 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.
+
+ Returns
+ -------
+ HttpResponse[CollectionItem]
+ Request was successful
+ """
+ _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=ItemsCreateItemRequestBody, direction="write"
+ ),
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CollectionItem,
+ parse_obj_as(
+ type_=CollectionItem, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def delete_items(
+ self,
+ collection_id: str,
+ *,
+ items: typing.Sequence[ItemsDeleteItemsRequestItemsItem],
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[None]:
+ """
+ Delete Items from a Collection.
+
+ Items will only be deleted in the primary locale unless a `cmsLocaleId` is included in the request.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ items : typing.Sequence[ItemsDeleteItemsRequestItemsItem]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[None]
+ """
+ _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(
+ object_=items, annotation=typing.Sequence[ItemsDeleteItemsRequestItemsItem], direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return HttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def update_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,
+ ) -> HttpResponse[ItemsUpdateItemsResponse]:
+ """
+ Update a single item or multiple items in a Collection.
+
+ 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`
+
+ Parameters
+ ----------
+ 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]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[ItemsUpdateItemsResponse]
+ Request was successful
+ """
+ _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"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ItemsUpdateItemsResponse,
+ parse_obj_as(
+ type_=ItemsUpdateItemsResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def list_items_live(
+ self,
+ collection_id: str,
+ *,
+ cms_locale_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ name: typing.Optional[str] = None,
+ slug: typing.Optional[str] = None,
+ last_published: typing.Optional[ItemsListItemsLiveRequestLastPublished] = None,
+ sort_by: typing.Optional[ItemsListItemsLiveRequestSortBy] = None,
+ sort_order: typing.Optional[ItemsListItemsLiveRequestSortOrder] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[CollectionItemList]:
+ """
+ List all published items in a collection.
+
+
+ Serving data to applications in real-time? Use the Content Delivery API at `api-cdn.webflow.com` for better performance. The CDN-backed endpoint is optimized for high-volume reads, while the Data API is designed for writes and management operations.
+
+
+ Required scope | `CMS:read`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ name : typing.Optional[str]
+ Filter by the exact name of the item(s)
+
+ slug : typing.Optional[str]
+ Filter by the exact slug of the item
+
+ last_published : typing.Optional[ItemsListItemsLiveRequestLastPublished]
+ Filter by the last published date of the item(s)
+
+ sort_by : typing.Optional[ItemsListItemsLiveRequestSortBy]
+ Sort results by the provided value
+
+ sort_order : typing.Optional[ItemsListItemsLiveRequestSortOrder]
+ Sorts the results by asc or desc
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[CollectionItemList]
+ Request was successful
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"collections/{jsonable_encoder(collection_id)}/items/live",
+ base_url=self._client_wrapper.get_environment().base,
+ method="GET",
+ params={
+ "cmsLocaleId": cms_locale_id,
+ "offset": offset,
+ "limit": limit,
+ "name": name,
+ "slug": slug,
+ "lastPublished": convert_and_respect_annotation_metadata(
+ object_=last_published, annotation=ItemsListItemsLiveRequestLastPublished, direction="write"
+ ),
+ "sortBy": sort_by,
+ "sortOrder": sort_order,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CollectionItemList,
+ parse_obj_as(
+ type_=CollectionItemList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def create_item_live(
+ self,
+ collection_id: str,
+ *,
+ request: ItemsCreateItemLiveRequestBody,
+ skip_invalid_files: typing.Optional[bool] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[CollectionItem]:
+ """
+ Create item(s) in a collection that will be immediately published to the live site.
+
+
+ To create items across multiple locales, [please use this endpoint.](/data/reference/cms/collection-items/staged-items/create-items)
+
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ 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.
+
+ Returns
+ -------
+ HttpResponse[CollectionItem]
+ Request was successful
+ """
+ _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=ItemsCreateItemLiveRequestBody, direction="write"
+ ),
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CollectionItem,
+ parse_obj_as(
+ type_=CollectionItem, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def delete_items_live(
+ self,
+ collection_id: str,
+ *,
+ items: typing.Sequence[ItemsDeleteItemsLiveRequestItemsItem],
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[None]:
+ """
+ Unpublish up to 100 items from the live site and set the `isDraft` property to `true`.
+
+ Items will only be unpublished in the primary locale unless a `cmsLocaleId` is included in the request.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ items : typing.Sequence[ItemsDeleteItemsLiveRequestItemsItem]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[None]
+ """
+ _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(
+ object_=items, annotation=typing.Sequence[ItemsDeleteItemsLiveRequestItemsItem], direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return HttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def 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,
+ ) -> HttpResponse[CollectionItemListNoPagination]:
+ """
+ Update a single published item or multiple published items (up to 100) in a Collection
+
+ Items will only be updated in the primary locale, unless a `cmsLocaleId` is included in the request.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ 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]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[CollectionItemListNoPagination]
+ Request was successful
+ """
+ _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"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CollectionItemListNoPagination,
+ parse_obj_as(
+ type_=CollectionItemListNoPagination, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def create_items(
+ self,
+ 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,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[BulkCollectionItem]:
+ """
+ Create an item or multiple items in a CMS Collection across multiple corresponding locales.
+
+
+ - This endpoint can create up to 100 items in a request.
+ - If the `cmsLocaleIds` parameter is not included in the request, an item will only be created in the primary locale.
+
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ 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
+
+ is_archived : typing.Optional[bool]
+ Indicates whether the item is archived.
+
+ is_draft : typing.Optional[bool]
+ Indicates whether the item is in draft state.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[BulkCollectionItem]
+ Request was successful
+ """
+ _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,
+ "isDraft": is_draft,
+ "fieldData": convert_and_respect_annotation_metadata(
+ object_=field_data, annotation=CreateBulkCollectionItemRequestBodyFieldData, direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ BulkCollectionItem,
+ parse_obj_as(
+ type_=BulkCollectionItem, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def get_item(
+ self,
+ collection_id: str,
+ item_id: str,
+ *,
+ cms_locale_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[CollectionItem]:
+ """
+ Get details of a selected Collection Item.
+
+ Required scope | `CMS:read`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ item_id : str
+ Unique identifier for an Item
+
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[CollectionItem]
+ Request was successful
+ """
+ _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="GET",
+ params={
+ "cmsLocaleId": cms_locale_id,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CollectionItem,
+ parse_obj_as(
+ type_=CollectionItem, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def delete_item(
+ self,
+ collection_id: str,
+ item_id: str,
+ *,
+ cms_locale_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[None]:
+ """
+ Delete an item from a collection.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ item_id : str
+ Unique identifier for an Item
+
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[None]
+ """
+ _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,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return HttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def update_item(
+ self,
+ 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,
+ last_updated: typing.Optional[str] = OMIT,
+ created_on: typing.Optional[str] = OMIT,
+ is_archived: typing.Optional[bool] = OMIT,
+ is_draft: typing.Optional[bool] = OMIT,
+ field_data: typing.Optional[CollectionItemPatchSingleFieldData] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[CollectionItem]:
+ """
+ Update a selected Item in a Collection.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ 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
+
+ cms_locale_id : typing.Optional[str]
+ Identifier for the locale of the CMS item
+
+ last_published : typing.Optional[str]
+ The date the item was last published
+
+ last_updated : typing.Optional[str]
+ The date the item was last updated
+
+ created_on : typing.Optional[str]
+ The date the item was created
+
+ is_archived : typing.Optional[bool]
+ Boolean determining if the Item is set to archived
+
+ is_draft : typing.Optional[bool]
+ Boolean determining if the Item is set to draft
+
+ field_data : typing.Optional[CollectionItemPatchSingleFieldData]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[CollectionItem]
+ Request was successful
+ """
+ _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,
+ "lastPublished": last_published,
+ "lastUpdated": last_updated,
+ "createdOn": created_on,
+ "isArchived": is_archived,
+ "isDraft": is_draft,
+ "fieldData": convert_and_respect_annotation_metadata(
+ object_=field_data, annotation=CollectionItemPatchSingleFieldData, direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CollectionItem,
+ parse_obj_as(
+ type_=CollectionItem, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def get_item_live(
+ self,
+ collection_id: str,
+ item_id: str,
+ *,
+ cms_locale_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[CollectionItem]:
+ """
+ Get details of a selected Collection live Item.
+
+
+ Serving data to applications in real-time? Use the Content Delivery API at `api-cdn.webflow.com` for better performance. The CDN-backed endpoint is optimized for high-volume reads, while the Data API is designed for writes and management operations.
+
+
+ Required scope | `CMS:read`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ item_id : str
+ Unique identifier for an Item
+
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[CollectionItem]
+ Request was successful
+ """
+ _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="GET",
+ params={
+ "cmsLocaleId": cms_locale_id,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CollectionItem,
+ parse_obj_as(
+ type_=CollectionItem, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def delete_item_live(
+ self,
+ collection_id: str,
+ item_id: str,
+ *,
+ cms_locale_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[None]:
+ """
+ Unpublish a live item from the site and set the `isDraft` property to `true`.
+
+ For bulk unpublishing, please use [this endpoint.](/data/v2.0.0/reference/cms/collection-items/live-items/delete-items-live)
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ item_id : str
+ Unique identifier for an Item
+
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[None]
+ """
+ _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,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return HttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def update_item_live(
+ self,
+ 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,
+ last_updated: typing.Optional[str] = OMIT,
+ created_on: typing.Optional[str] = OMIT,
+ is_archived: typing.Optional[bool] = OMIT,
+ is_draft: typing.Optional[bool] = OMIT,
+ field_data: typing.Optional[CollectionItemPatchSingleFieldData] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[CollectionItem]:
+ """
+ Update a selected live Item in a Collection. The updates for this Item will be published to the live site.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ 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
+
+ cms_locale_id : typing.Optional[str]
+ Identifier for the locale of the CMS item
+
+ last_published : typing.Optional[str]
+ The date the item was last published
+
+ last_updated : typing.Optional[str]
+ The date the item was last updated
+
+ created_on : typing.Optional[str]
+ The date the item was created
+
+ is_archived : typing.Optional[bool]
+ Boolean determining if the Item is set to archived
+
+ is_draft : typing.Optional[bool]
+ Boolean determining if the Item is set to draft
+
+ field_data : typing.Optional[CollectionItemPatchSingleFieldData]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[CollectionItem]
+ Request was successful
+ """
+ _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,
+ "lastPublished": last_published,
+ "lastUpdated": last_updated,
+ "createdOn": created_on,
+ "isArchived": is_archived,
+ "isDraft": is_draft,
+ "fieldData": convert_and_respect_annotation_metadata(
+ object_=field_data, annotation=CollectionItemPatchSingleFieldData, direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CollectionItem,
+ parse_obj_as(
+ type_=CollectionItem, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def publish_item(
+ self,
+ collection_id: str,
+ *,
+ request: ItemsPublishItemRequest,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[ItemsPublishItemResponse]:
+ """
+ Publish an item or multiple items.
+
+ Required scope | `cms:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ request : ItemsPublishItemRequest
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[ItemsPublishItemResponse]
+ Request was successful
+ """
+ _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=convert_and_respect_annotation_metadata(
+ object_=request, annotation=ItemsPublishItemRequest, direction="write"
+ ),
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ItemsPublishItemResponse,
+ parse_obj_as(
+ type_=ItemsPublishItemResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawItemsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def list_items(
+ self,
+ collection_id: str,
+ *,
+ cms_locale_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ name: typing.Optional[str] = None,
+ slug: typing.Optional[str] = None,
+ last_published: typing.Optional[ItemsListItemsRequestLastPublished] = None,
+ sort_by: typing.Optional[ItemsListItemsRequestSortBy] = None,
+ sort_order: typing.Optional[ItemsListItemsRequestSortOrder] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[CollectionItemList]:
+ """
+ List of all Items within a Collection.
+
+ Required scope | `CMS:read`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ name : typing.Optional[str]
+ Filter by the exact name of the item(s)
+
+ slug : typing.Optional[str]
+ Filter by the exact slug of the item
+
+ last_published : typing.Optional[ItemsListItemsRequestLastPublished]
+ Filter by the last published date of the item(s)
+
+ sort_by : typing.Optional[ItemsListItemsRequestSortBy]
+ Sort results by the provided value
+
+ sort_order : typing.Optional[ItemsListItemsRequestSortOrder]
+ Sorts the results by asc or desc
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[CollectionItemList]
+ Request was successful
+ """
+ _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,
+ "offset": offset,
+ "limit": limit,
+ "name": name,
+ "slug": slug,
+ "lastPublished": convert_and_respect_annotation_metadata(
+ object_=last_published, annotation=ItemsListItemsRequestLastPublished, direction="write"
+ ),
+ "sortBy": sort_by,
+ "sortOrder": sort_order,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CollectionItemList,
+ parse_obj_as(
+ type_=CollectionItemList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def create_item(
+ self,
+ collection_id: str,
+ *,
+ request: ItemsCreateItemRequestBody,
+ skip_invalid_files: typing.Optional[bool] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[CollectionItem]:
+ """
+ Create Item(s) in a Collection.
+
+
+ To create items across multiple locales, please use [this endpoint.](/data/reference/cms/collection-items/staged-items/create-items)
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ 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.
+
+ Returns
+ -------
+ AsyncHttpResponse[CollectionItem]
+ Request was successful
+ """
+ _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=ItemsCreateItemRequestBody, direction="write"
+ ),
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CollectionItem,
+ parse_obj_as(
+ type_=CollectionItem, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def delete_items(
+ self,
+ collection_id: str,
+ *,
+ items: typing.Sequence[ItemsDeleteItemsRequestItemsItem],
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[None]:
+ """
+ Delete Items from a Collection.
+
+ Items will only be deleted in the primary locale unless a `cmsLocaleId` is included in the request.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ items : typing.Sequence[ItemsDeleteItemsRequestItemsItem]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[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(
+ object_=items, annotation=typing.Sequence[ItemsDeleteItemsRequestItemsItem], direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return AsyncHttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def update_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,
+ ) -> AsyncHttpResponse[ItemsUpdateItemsResponse]:
+ """
+ Update a single item or multiple items in a Collection.
+
+ 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`
+
+ Parameters
+ ----------
+ 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]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[ItemsUpdateItemsResponse]
+ Request was successful
+ """
+ _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"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ItemsUpdateItemsResponse,
+ parse_obj_as(
+ type_=ItemsUpdateItemsResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def list_items_live(
+ self,
+ collection_id: str,
+ *,
+ cms_locale_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ name: typing.Optional[str] = None,
+ slug: typing.Optional[str] = None,
+ last_published: typing.Optional[ItemsListItemsLiveRequestLastPublished] = None,
+ sort_by: typing.Optional[ItemsListItemsLiveRequestSortBy] = None,
+ sort_order: typing.Optional[ItemsListItemsLiveRequestSortOrder] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[CollectionItemList]:
+ """
+ List all published items in a collection.
+
+
+ Serving data to applications in real-time? Use the Content Delivery API at `api-cdn.webflow.com` for better performance. The CDN-backed endpoint is optimized for high-volume reads, while the Data API is designed for writes and management operations.
+
+
+ Required scope | `CMS:read`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ name : typing.Optional[str]
+ Filter by the exact name of the item(s)
+
+ slug : typing.Optional[str]
+ Filter by the exact slug of the item
+
+ last_published : typing.Optional[ItemsListItemsLiveRequestLastPublished]
+ Filter by the last published date of the item(s)
+
+ sort_by : typing.Optional[ItemsListItemsLiveRequestSortBy]
+ Sort results by the provided value
+
+ sort_order : typing.Optional[ItemsListItemsLiveRequestSortOrder]
+ Sorts the results by asc or desc
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[CollectionItemList]
+ Request was successful
+ """
+ _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="GET",
+ params={
+ "cmsLocaleId": cms_locale_id,
+ "offset": offset,
+ "limit": limit,
+ "name": name,
+ "slug": slug,
+ "lastPublished": convert_and_respect_annotation_metadata(
+ object_=last_published, annotation=ItemsListItemsLiveRequestLastPublished, direction="write"
+ ),
+ "sortBy": sort_by,
+ "sortOrder": sort_order,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CollectionItemList,
+ parse_obj_as(
+ type_=CollectionItemList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def create_item_live(
+ self,
+ collection_id: str,
+ *,
+ request: ItemsCreateItemLiveRequestBody,
+ skip_invalid_files: typing.Optional[bool] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[CollectionItem]:
+ """
+ Create item(s) in a collection that will be immediately published to the live site.
+
+
+ To create items across multiple locales, [please use this endpoint.](/data/reference/cms/collection-items/staged-items/create-items)
+
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ 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.
+
+ Returns
+ -------
+ AsyncHttpResponse[CollectionItem]
+ Request was successful
+ """
+ _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=ItemsCreateItemLiveRequestBody, direction="write"
+ ),
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CollectionItem,
+ parse_obj_as(
+ type_=CollectionItem, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def delete_items_live(
+ self,
+ collection_id: str,
+ *,
+ items: typing.Sequence[ItemsDeleteItemsLiveRequestItemsItem],
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[None]:
+ """
+ Unpublish up to 100 items from the live site and set the `isDraft` property to `true`.
+
+ Items will only be unpublished in the primary locale unless a `cmsLocaleId` is included in the request.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ items : typing.Sequence[ItemsDeleteItemsLiveRequestItemsItem]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[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(
+ object_=items, annotation=typing.Sequence[ItemsDeleteItemsLiveRequestItemsItem], direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return AsyncHttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def 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,
+ ) -> AsyncHttpResponse[CollectionItemListNoPagination]:
+ """
+ Update a single published item or multiple published items (up to 100) in a Collection
+
+ Items will only be updated in the primary locale, unless a `cmsLocaleId` is included in the request.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ 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]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[CollectionItemListNoPagination]
+ Request was successful
+ """
+ _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"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CollectionItemListNoPagination,
+ parse_obj_as(
+ type_=CollectionItemListNoPagination, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def create_items(
+ self,
+ 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,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[BulkCollectionItem]:
+ """
+ Create an item or multiple items in a CMS Collection across multiple corresponding locales.
+
+
+ - This endpoint can create up to 100 items in a request.
+ - If the `cmsLocaleIds` parameter is not included in the request, an item will only be created in the primary locale.
+
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ 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
+
+ is_archived : typing.Optional[bool]
+ Indicates whether the item is archived.
+
+ is_draft : typing.Optional[bool]
+ Indicates whether the item is in draft state.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[BulkCollectionItem]
+ Request was successful
+ """
+ _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,
+ "isDraft": is_draft,
+ "fieldData": convert_and_respect_annotation_metadata(
+ object_=field_data, annotation=CreateBulkCollectionItemRequestBodyFieldData, direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ BulkCollectionItem,
+ parse_obj_as(
+ type_=BulkCollectionItem, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def get_item(
+ self,
+ collection_id: str,
+ item_id: str,
+ *,
+ cms_locale_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[CollectionItem]:
+ """
+ Get details of a selected Collection Item.
+
+ Required scope | `CMS:read`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ item_id : str
+ Unique identifier for an Item
+
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[CollectionItem]
+ Request was successful
+ """
+ _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="GET",
+ params={
+ "cmsLocaleId": cms_locale_id,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CollectionItem,
+ parse_obj_as(
+ type_=CollectionItem, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def delete_item(
+ self,
+ collection_id: str,
+ item_id: str,
+ *,
+ cms_locale_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[None]:
+ """
+ Delete an item from a collection.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ item_id : str
+ Unique identifier for an Item
+
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[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,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return AsyncHttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def update_item(
+ self,
+ 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,
+ last_updated: typing.Optional[str] = OMIT,
+ created_on: typing.Optional[str] = OMIT,
+ is_archived: typing.Optional[bool] = OMIT,
+ is_draft: typing.Optional[bool] = OMIT,
+ field_data: typing.Optional[CollectionItemPatchSingleFieldData] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[CollectionItem]:
+ """
+ Update a selected Item in a Collection.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ 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
+
+ cms_locale_id : typing.Optional[str]
+ Identifier for the locale of the CMS item
+
+ last_published : typing.Optional[str]
+ The date the item was last published
+
+ last_updated : typing.Optional[str]
+ The date the item was last updated
+
+ created_on : typing.Optional[str]
+ The date the item was created
+
+ is_archived : typing.Optional[bool]
+ Boolean determining if the Item is set to archived
+
+ is_draft : typing.Optional[bool]
+ Boolean determining if the Item is set to draft
+
+ field_data : typing.Optional[CollectionItemPatchSingleFieldData]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[CollectionItem]
+ Request was successful
+ """
+ _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,
+ "lastPublished": last_published,
+ "lastUpdated": last_updated,
+ "createdOn": created_on,
+ "isArchived": is_archived,
+ "isDraft": is_draft,
+ "fieldData": convert_and_respect_annotation_metadata(
+ object_=field_data, annotation=CollectionItemPatchSingleFieldData, direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CollectionItem,
+ parse_obj_as(
+ type_=CollectionItem, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def get_item_live(
+ self,
+ collection_id: str,
+ item_id: str,
+ *,
+ cms_locale_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[CollectionItem]:
+ """
+ Get details of a selected Collection live Item.
+
+
+ Serving data to applications in real-time? Use the Content Delivery API at `api-cdn.webflow.com` for better performance. The CDN-backed endpoint is optimized for high-volume reads, while the Data API is designed for writes and management operations.
+
+
+ Required scope | `CMS:read`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ item_id : str
+ Unique identifier for an Item
+
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[CollectionItem]
+ Request was successful
+ """
+ _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="GET",
+ params={
+ "cmsLocaleId": cms_locale_id,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CollectionItem,
+ parse_obj_as(
+ type_=CollectionItem, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def delete_item_live(
+ self,
+ collection_id: str,
+ item_id: str,
+ *,
+ cms_locale_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[None]:
+ """
+ Unpublish a live item from the site and set the `isDraft` property to `true`.
+
+ For bulk unpublishing, please use [this endpoint.](/data/v2.0.0/reference/cms/collection-items/live-items/delete-items-live)
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ item_id : str
+ Unique identifier for an Item
+
+ cms_locale_id : typing.Optional[str]
+ Unique identifier for a CMS Locale. This UID is different from the Site locale identifier and is listed as `cmsLocaleId` in the Sites response. To query multiple locales, input a comma separated string.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[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,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return AsyncHttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def update_item_live(
+ self,
+ 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,
+ last_updated: typing.Optional[str] = OMIT,
+ created_on: typing.Optional[str] = OMIT,
+ is_archived: typing.Optional[bool] = OMIT,
+ is_draft: typing.Optional[bool] = OMIT,
+ field_data: typing.Optional[CollectionItemPatchSingleFieldData] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[CollectionItem]:
+ """
+ Update a selected live Item in a Collection. The updates for this Item will be published to the live site.
+
+ Required scope | `CMS:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ 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
+
+ cms_locale_id : typing.Optional[str]
+ Identifier for the locale of the CMS item
+
+ last_published : typing.Optional[str]
+ The date the item was last published
+
+ last_updated : typing.Optional[str]
+ The date the item was last updated
+
+ created_on : typing.Optional[str]
+ The date the item was created
+
+ is_archived : typing.Optional[bool]
+ Boolean determining if the Item is set to archived
+
+ is_draft : typing.Optional[bool]
+ Boolean determining if the Item is set to draft
+
+ field_data : typing.Optional[CollectionItemPatchSingleFieldData]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[CollectionItem]
+ Request was successful
+ """
+ _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,
+ "lastPublished": last_published,
+ "lastUpdated": last_updated,
+ "createdOn": created_on,
+ "isArchived": is_archived,
+ "isDraft": is_draft,
+ "fieldData": convert_and_respect_annotation_metadata(
+ object_=field_data, annotation=CollectionItemPatchSingleFieldData, direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CollectionItem,
+ parse_obj_as(
+ type_=CollectionItem, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def publish_item(
+ self,
+ collection_id: str,
+ *,
+ request: ItemsPublishItemRequest,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[ItemsPublishItemResponse]:
+ """
+ Publish an item or multiple items.
+
+ Required scope | `cms:write`
+
+ Parameters
+ ----------
+ collection_id : str
+ Unique identifier for a Collection
+
+ request : ItemsPublishItemRequest
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[ItemsPublishItemResponse]
+ Request was successful
+ """
+ _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=convert_and_respect_annotation_metadata(
+ object_=request, annotation=ItemsPublishItemRequest, direction="write"
+ ),
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ItemsPublishItemResponse,
+ parse_obj_as(
+ type_=ItemsPublishItemResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/collections/resources/items/types/__init__.py b/src/webflow/resources/collections/resources/items/types/__init__.py
index b313482..6350593 100644
--- a/src/webflow/resources/collections/resources/items/types/__init__.py
+++ b/src/webflow/resources/collections/resources/items/types/__init__.py
@@ -1,6 +1,94 @@
# This file was auto-generated by Fern from our API Definition.
-from .bulk_collection_item_field_data import BulkCollectionItemFieldData
-from .items_publish_item_response import ItemsPublishItemResponse
+# isort: skip_file
-__all__ = ["BulkCollectionItemFieldData", "ItemsPublishItemResponse"]
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .create_bulk_collection_item_request_body_field_data import CreateBulkCollectionItemRequestBodyFieldData
+ from .create_bulk_collection_item_request_body_field_data_one_item import (
+ CreateBulkCollectionItemRequestBodyFieldDataOneItem,
+ )
+ 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
+_dynamic_imports: typing.Dict[str, str] = {
+ "CreateBulkCollectionItemRequestBodyFieldData": ".create_bulk_collection_item_request_body_field_data",
+ "CreateBulkCollectionItemRequestBodyFieldDataOneItem": ".create_bulk_collection_item_request_body_field_data_one_item",
+ "ItemIDs": ".item_i_ds",
+ "ItemIDsWithLocales": ".item_i_ds_with_locales",
+ "ItemsCreateItemLiveRequestBody": ".items_create_item_live_request_body",
+ "ItemsCreateItemRequestBody": ".items_create_item_request_body",
+ "ItemsDeleteItemsLiveRequestItemsItem": ".items_delete_items_live_request_items_item",
+ "ItemsDeleteItemsRequestItemsItem": ".items_delete_items_request_items_item",
+ "ItemsListItemsLiveRequestSortBy": ".items_list_items_live_request_sort_by",
+ "ItemsListItemsLiveRequestSortOrder": ".items_list_items_live_request_sort_order",
+ "ItemsListItemsRequestSortBy": ".items_list_items_request_sort_by",
+ "ItemsListItemsRequestSortOrder": ".items_list_items_request_sort_order",
+ "ItemsPublishItemRequest": ".items_publish_item_request",
+ "ItemsPublishItemRequestItemsItemsItem": ".items_publish_item_request_items_items_item",
+ "ItemsPublishItemResponse": ".items_publish_item_response",
+ "ItemsUpdateItemsResponse": ".items_update_items_response",
+ "MultipleItems": ".multiple_items",
+ "MultipleLiveItems": ".multiple_live_items",
+ "SingleCmsItem": ".single_cms_item",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = [
+ "CreateBulkCollectionItemRequestBodyFieldData",
+ "CreateBulkCollectionItemRequestBodyFieldDataOneItem",
+ "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/bulk_collection_item_field_data.py b/src/webflow/resources/collections/resources/items/types/bulk_collection_item_field_data.py
deleted file mode 100644
index 18cb175..0000000
--- a/src/webflow/resources/collections/resources/items/types/bulk_collection_item_field_data.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import datetime as dt
-import typing
-
-from ......core.datetime_utils import serialize_datetime
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class BulkCollectionItemFieldData(pydantic.BaseModel):
- name: typing.Optional[str] = pydantic.Field(default=None, description="Name of the Item")
- slug: typing.Optional[str] = pydantic.Field(
- default=None,
- description="URL structure of the Item in your site. Note: Updates to an item slug will break all links referencing the old slug.",
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- json_encoders = {dt.datetime: serialize_datetime}
diff --git a/src/webflow/resources/collections/resources/items/types/create_bulk_collection_item_request_body_field_data.py b/src/webflow/resources/collections/resources/items/types/create_bulk_collection_item_request_body_field_data.py
new file mode 100644
index 0000000..cfa74ad
--- /dev/null
+++ b/src/webflow/resources/collections/resources/items/types/create_bulk_collection_item_request_body_field_data.py
@@ -0,0 +1,12 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from .create_bulk_collection_item_request_body_field_data_one_item import (
+ CreateBulkCollectionItemRequestBodyFieldDataOneItem,
+)
+from .single_cms_item import SingleCmsItem
+
+CreateBulkCollectionItemRequestBodyFieldData = typing.Union[
+ SingleCmsItem, typing.List[CreateBulkCollectionItemRequestBodyFieldDataOneItem]
+]
diff --git a/src/webflow/resources/collections/resources/items/types/create_bulk_collection_item_request_body_field_data_one_item.py b/src/webflow/resources/collections/resources/items/types/create_bulk_collection_item_request_body_field_data_one_item.py
new file mode 100644
index 0000000..0999f96
--- /dev/null
+++ b/src/webflow/resources/collections/resources/items/types/create_bulk_collection_item_request_body_field_data_one_item.py
@@ -0,0 +1,32 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ......core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class CreateBulkCollectionItemRequestBodyFieldDataOneItem(UniversalBaseModel):
+ """
+ A single CMS item to create
+ """
+
+ name: str = pydantic.Field()
+ """
+ The name of the item.
+ """
+
+ slug: str = pydantic.Field()
+ """
+ URL slug for the item in your site.
+ Note: Updating the item slug will break all links referencing the old slug.
+ """
+
+ 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.py b/src/webflow/resources/collections/resources/items/types/item_i_ds.py
new file mode 100644
index 0000000..f71ca26
--- /dev/null
+++ b/src/webflow/resources/collections/resources/items/types/item_i_ds.py
@@ -0,0 +1,27 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ......core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ......core.serialization import FieldMetadata
+
+
+class ItemIDs(UniversalBaseModel):
+ """
+ An array of Item IDs in a single locale
+ """
+
+ item_ids: typing_extensions.Annotated[
+ typing.Optional[typing.List[str]], FieldMetadata(alias="itemIds"), pydantic.Field(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..23ad969
--- /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.
+
+import typing
+
+import pydantic
+from ......core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .items_publish_item_request_items_items_item import ItemsPublishItemRequestItemsItemsItem
+
+
+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_body.py b/src/webflow/resources/collections/resources/items/types/items_create_item_live_request_body.py
new file mode 100644
index 0000000..7e008a5
--- /dev/null
+++ b/src/webflow/resources/collections/resources/items/types/items_create_item_live_request_body.py
@@ -0,0 +1,8 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from ......types.collection_item import CollectionItem
+from .multiple_live_items import MultipleLiveItems
+
+ItemsCreateItemLiveRequestBody = typing.Union[CollectionItem, MultipleLiveItems]
diff --git a/src/webflow/resources/collections/resources/items/types/items_create_item_request_body.py b/src/webflow/resources/collections/resources/items/types/items_create_item_request_body.py
new file mode 100644
index 0000000..94bd556
--- /dev/null
+++ b/src/webflow/resources/collections/resources/items/types/items_create_item_request_body.py
@@ -0,0 +1,8 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from ......types.collection_item_post_single import CollectionItemPostSingle
+from .multiple_items import 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
new file mode 100644
index 0000000..0fa1b7b
--- /dev/null
+++ b/src/webflow/resources/collections/resources/items/types/items_delete_items_live_request_items_item.py
@@ -0,0 +1,32 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ......core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ......core.serialization import FieldMetadata
+
+
+class ItemsDeleteItemsLiveRequestItemsItem(UniversalBaseModel):
+ id: str = pydantic.Field()
+ """
+ Unique identifier for the Item
+ """
+
+ cms_locale_ids: typing_extensions.Annotated[
+ typing.Optional[typing.List[str]],
+ FieldMetadata(alias="cmsLocaleIds"),
+ pydantic.Field(
+ alias="cmsLocaleIds", description="Array of identifiers for the locales where the item will be created"
+ ),
+ ] = 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_delete_items_request_items_item.py b/src/webflow/resources/collections/resources/items/types/items_delete_items_request_items_item.py
new file mode 100644
index 0000000..5438d65
--- /dev/null
+++ b/src/webflow/resources/collections/resources/items/types/items_delete_items_request_items_item.py
@@ -0,0 +1,32 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ......core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ......core.serialization import FieldMetadata
+
+
+class ItemsDeleteItemsRequestItemsItem(UniversalBaseModel):
+ id: str = pydantic.Field()
+ """
+ Unique identifier for the Item
+ """
+
+ cms_locale_ids: typing_extensions.Annotated[
+ typing.Optional[typing.List[str]],
+ FieldMetadata(alias="cmsLocaleIds"),
+ pydantic.Field(
+ alias="cmsLocaleIds", description="Array of identifiers for the locales where the item will be created"
+ ),
+ ] = 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_list_items_live_request_sort_by.py b/src/webflow/resources/collections/resources/items/types/items_list_items_live_request_sort_by.py
new file mode 100644
index 0000000..9929480
--- /dev/null
+++ b/src/webflow/resources/collections/resources/items/types/items_list_items_live_request_sort_by.py
@@ -0,0 +1,5 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+ItemsListItemsLiveRequestSortBy = typing.Union[typing.Literal["lastPublished", "name", "slug"], typing.Any]
diff --git a/src/webflow/resources/collections/resources/items/types/items_list_items_live_request_sort_order.py b/src/webflow/resources/collections/resources/items/types/items_list_items_live_request_sort_order.py
new file mode 100644
index 0000000..5666223
--- /dev/null
+++ b/src/webflow/resources/collections/resources/items/types/items_list_items_live_request_sort_order.py
@@ -0,0 +1,5 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+ItemsListItemsLiveRequestSortOrder = typing.Union[typing.Literal["asc", "desc"], typing.Any]
diff --git a/src/webflow/resources/collections/resources/items/types/items_list_items_request_sort_by.py b/src/webflow/resources/collections/resources/items/types/items_list_items_request_sort_by.py
new file mode 100644
index 0000000..222d1ff
--- /dev/null
+++ b/src/webflow/resources/collections/resources/items/types/items_list_items_request_sort_by.py
@@ -0,0 +1,5 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+ItemsListItemsRequestSortBy = typing.Union[typing.Literal["lastPublished", "name", "slug"], typing.Any]
diff --git a/src/webflow/resources/collections/resources/items/types/items_list_items_request_sort_order.py b/src/webflow/resources/collections/resources/items/types/items_list_items_request_sort_order.py
new file mode 100644
index 0000000..887dfcc
--- /dev/null
+++ b/src/webflow/resources/collections/resources/items/types/items_list_items_request_sort_order.py
@@ -0,0 +1,5 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+ItemsListItemsRequestSortOrder = typing.Union[typing.Literal["asc", "desc"], typing.Any]
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..dc4ca56
--- /dev/null
+++ b/src/webflow/resources/collections/resources/items/types/items_publish_item_request.py
@@ -0,0 +1,8 @@
+# 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..6798991
--- /dev/null
+++ b/src/webflow/resources/collections/resources/items/types/items_publish_item_request_items_items_item.py
@@ -0,0 +1,32 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ......core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ......core.serialization import FieldMetadata
+
+
+class 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(
+ alias="cmsLocaleIds", description="Array of identifiers for the locales where the item will be published"
+ ),
+ ] = 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_publish_item_response.py b/src/webflow/resources/collections/resources/items/types/items_publish_item_response.py
index 0ecc85f..4e5d67e 100644
--- a/src/webflow/resources/collections/resources/items/types/items_publish_item_response.py
+++ b/src/webflow/resources/collections/resources/items/types/items_publish_item_response.py
@@ -1,30 +1,26 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ......core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ......core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ......core.serialization import FieldMetadata
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class ItemsPublishItemResponse(pydantic.BaseModel):
- published_item_ids: typing.Optional[typing.List[str]] = pydantic.Field(alias="publishedItemIds", default=None)
+class ItemsPublishItemResponse(UniversalBaseModel):
+ published_item_ids: typing_extensions.Annotated[
+ typing.Optional[typing.List[str]],
+ FieldMetadata(alias="publishedItemIds"),
+ pydantic.Field(alias="publishedItemIds"),
+ ] = None
errors: typing.Optional[typing.List[str]] = None
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ 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..137ac3f
--- /dev/null
+++ b/src/webflow/resources/collections/resources/items/types/items_update_items_response.py
@@ -0,0 +1,8 @@
+# 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/collections/resources/items/types/multiple_items.py b/src/webflow/resources/collections/resources/items/types/multiple_items.py
new file mode 100644
index 0000000..44eed57
--- /dev/null
+++ b/src/webflow/resources/collections/resources/items/types/multiple_items.py
@@ -0,0 +1,23 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ......core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ......types.collection_item_post_single import CollectionItemPostSingle
+
+
+class MultipleItems(UniversalBaseModel):
+ items: typing.Optional[typing.List[CollectionItemPostSingle]] = pydantic.Field(default=None)
+ """
+ An array of items to create
+ """
+
+ 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/multiple_live_items.py b/src/webflow/resources/collections/resources/items/types/multiple_live_items.py
new file mode 100644
index 0000000..8661342
--- /dev/null
+++ b/src/webflow/resources/collections/resources/items/types/multiple_live_items.py
@@ -0,0 +1,23 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ......core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ......types.collection_item import CollectionItem
+
+
+class MultipleLiveItems(UniversalBaseModel):
+ items: typing.Optional[typing.List[CollectionItem]] = pydantic.Field(default=None)
+ """
+ List of collection items to create
+ """
+
+ 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/single_cms_item.py b/src/webflow/resources/collections/resources/items/types/single_cms_item.py
new file mode 100644
index 0000000..176d013
--- /dev/null
+++ b/src/webflow/resources/collections/resources/items/types/single_cms_item.py
@@ -0,0 +1,28 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ......core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class SingleCmsItem(UniversalBaseModel):
+ name: str = pydantic.Field()
+ """
+ The name of the item.
+ """
+
+ slug: str = pydantic.Field()
+ """
+ URL slug for the item in your site.
+ Note: Updating the item slug will break all links referencing the old slug.
+ """
+
+ 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/components/__init__.py b/src/webflow/resources/components/__init__.py
new file mode 100644
index 0000000..7b65fd3
--- /dev/null
+++ b/src/webflow/resources/components/__init__.py
@@ -0,0 +1,49 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .types import (
+ ComponentDomWriteNodesItem,
+ ComponentPropertiesWritePropertiesItem,
+ ComponentsUpdateContentResponse,
+ ComponentsUpdatePropertiesResponse,
+ )
+_dynamic_imports: typing.Dict[str, str] = {
+ "ComponentDomWriteNodesItem": ".types",
+ "ComponentPropertiesWritePropertiesItem": ".types",
+ "ComponentsUpdateContentResponse": ".types",
+ "ComponentsUpdatePropertiesResponse": ".types",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = [
+ "ComponentDomWriteNodesItem",
+ "ComponentPropertiesWritePropertiesItem",
+ "ComponentsUpdateContentResponse",
+ "ComponentsUpdatePropertiesResponse",
+]
diff --git a/src/webflow/resources/components/client.py b/src/webflow/resources/components/client.py
new file mode 100644
index 0000000..a9584d8
--- /dev/null
+++ b/src/webflow/resources/components/client.py
@@ -0,0 +1,925 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.request_options import RequestOptions
+from ...types.component_dom import ComponentDom
+from ...types.component_list import ComponentList
+from ...types.component_properties import ComponentProperties
+from .raw_client import AsyncRawComponentsClient, RawComponentsClient
+from .types.component_dom_write_nodes_item import ComponentDomWriteNodesItem
+from .types.component_properties_write_properties_item import ComponentPropertiesWritePropertiesItem
+from .types.components_update_content_response import ComponentsUpdateContentResponse
+from .types.components_update_properties_response import ComponentsUpdatePropertiesResponse
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class ComponentsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._raw_client = RawComponentsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawComponentsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawComponentsClient
+ """
+ return self._raw_client
+
+ def list(
+ self,
+ site_id: str,
+ *,
+ branch_id: typing.Optional[str] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ComponentList:
+ """
+ List of all components for a site.
+
+ Required scope | `components:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ branch_id : typing.Optional[str]
+ Scope the operation to work on a specific branch.
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ComponentList
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.components.list(
+ site_id="580e63e98c9a982ac9b8b741",
+ branch_id="68026fa68ef6dc744c75b833",
+ limit=1,
+ offset=1,
+ )
+ """
+ _response = self._raw_client.list(
+ site_id, branch_id=branch_id, limit=limit, offset=offset, request_options=request_options
+ )
+ return _response.data
+
+ def get_content(
+ self,
+ site_id: str,
+ component_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ branch_id: typing.Optional[str] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ComponentDom:
+ """
+ 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.
+
+ Required scope | `components:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ component_id : str
+ Unique identifier for a Component
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ branch_id : typing.Optional[str]
+ Scope the operation to work on a specific branch.
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ComponentDom
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.components.get_content(
+ site_id="580e63e98c9a982ac9b8b741",
+ component_id="8505ba55-ef72-629e-f85c-33e4b703d48b",
+ locale_id="65427cf400e02b306eaa04a0",
+ branch_id="68026fa68ef6dc744c75b833",
+ limit=1,
+ offset=1,
+ )
+ """
+ _response = self._raw_client.get_content(
+ site_id,
+ component_id,
+ locale_id=locale_id,
+ branch_id=branch_id,
+ limit=limit,
+ offset=offset,
+ request_options=request_options,
+ )
+ return _response.data
+
+ def update_content(
+ self,
+ site_id: str,
+ component_id: str,
+ *,
+ nodes: typing.Sequence[ComponentDomWriteNodesItem],
+ locale_id: typing.Optional[str] = None,
+ branch_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ComponentsUpdateContentResponse:
+ """
+ This endpoint updates content within a component defintion for **secondary locales**. It supports updating up to 1000 nodes in a single request.
+
+ Before making updates:
+ 1. Use the [get component content](/data/reference/pages-and-components/components/get-content) endpoint to identify available content nodes and their types.
+ 2. If your component definition has a component instance nested within it, retrieve the nested component instance's properties that you'll override using the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint.
+ 3. DOM elements may include a `data-w-id` attribute. This attribute is used by Webflow to maintain custom attributes and links across locales. Always include the original `data-w-id` value in your update requests to ensure consistent behavior across all locales.
+
+
+ This endpoint is specifically for localizing component definitions. Ensure that the specified `localeId` is a valid **secondary locale** for the site otherwise the request will fail.
+
+
+ Required scope | `components:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ component_id : str
+ Unique identifier for a Component
+
+ nodes : typing.Sequence[ComponentDomWriteNodesItem]
+ List of DOM Nodes with the new content that will be updated in each node.
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ branch_id : typing.Optional[str]
+ Scope the operation to work on a specific branch.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ComponentsUpdateContentResponse
+ Request was successful
+
+ Examples
+ --------
+ from webflow import (
+ ComponentInstanceNodePropertyOverridesWrite,
+ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem,
+ Select,
+ SelectNodeWriteChoicesItem,
+ SubmitButtonNodeWrite,
+ TextInputNodeWrite,
+ TextNodeWrite,
+ Webflow,
+ )
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.components.update_content(
+ site_id="580e63e98c9a982ac9b8b741",
+ component_id="8505ba55-ef72-629e-f85c-33e4b703d48b",
+ locale_id="65427cf400e02b306eaa04a0",
+ branch_id="68026fa68ef6dc744c75b833",
+ nodes=[
+ TextNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad623",
+ text="
The Hitchhiker's Guide to the Galaxy ",
+ ),
+ TextNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad627",
+ text="Don't Panic! Always know where your towel is.
",
+ ),
+ Select(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad635",
+ choices=[
+ SelectNodeWriteChoicesItem(
+ value="choice-1",
+ text="First choice",
+ ),
+ SelectNodeWriteChoicesItem(
+ value="choice-2",
+ text="Second choice",
+ ),
+ ],
+ ),
+ TextInputNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad642",
+ placeholder="Enter something here...",
+ ),
+ SubmitButtonNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad671",
+ value="Submit",
+ waiting_text="Submitting...",
+ ),
+ ComponentInstanceNodePropertyOverridesWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad629",
+ property_overrides=[
+ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem(
+ property_id="7dd14c08-2e96-8d3d-2b19-b5c03642a0f0",
+ text="
Time is an illusion ",
+ ),
+ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem(
+ property_id="7dd14c08-2e96-8d3d-2b19-b5c03642a0f1",
+ text="Life, the Universe and Everything",
+ ),
+ ],
+ ),
+ ],
+ )
+ """
+ _response = self._raw_client.update_content(
+ site_id,
+ component_id,
+ nodes=nodes,
+ locale_id=locale_id,
+ branch_id=branch_id,
+ request_options=request_options,
+ )
+ return _response.data
+
+ def get_properties(
+ self,
+ site_id: str,
+ component_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ branch_id: typing.Optional[str] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ComponentProperties:
+ """
+ Get the default property values of a component definition.
+
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ component_id : str
+ Unique identifier for a Component
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ branch_id : typing.Optional[str]
+ Scope the operation to work on a specific branch.
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ComponentProperties
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.components.get_properties(
+ site_id="580e63e98c9a982ac9b8b741",
+ component_id="8505ba55-ef72-629e-f85c-33e4b703d48b",
+ locale_id="65427cf400e02b306eaa04a0",
+ branch_id="68026fa68ef6dc744c75b833",
+ limit=1,
+ offset=1,
+ )
+ """
+ _response = self._raw_client.get_properties(
+ site_id,
+ component_id,
+ locale_id=locale_id,
+ branch_id=branch_id,
+ limit=limit,
+ offset=offset,
+ request_options=request_options,
+ )
+ return _response.data
+
+ def update_properties(
+ self,
+ site_id: str,
+ component_id: str,
+ *,
+ properties: typing.Sequence[ComponentPropertiesWritePropertiesItem],
+ locale_id: typing.Optional[str] = None,
+ branch_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ComponentsUpdatePropertiesResponse:
+ """
+ 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 properties that can be updated in a secondary locale.
+ 2. Rich Text properties may include a `data-w-id` attribute. This attribute is used by Webflow to maintain links across locales. Always include the original `data-w-id` value in your update requests to ensure consistent behavior across all locales.
+
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ component_id : str
+ Unique identifier for a Component
+
+ properties : typing.Sequence[ComponentPropertiesWritePropertiesItem]
+ A list of component properties to update within the specified secondary locale.
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ branch_id : typing.Optional[str]
+ Scope the operation to work on a specific branch.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ComponentsUpdatePropertiesResponse
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
+ from webflow.resources.components import ComponentPropertiesWritePropertiesItem
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.components.update_properties(
+ site_id="580e63e98c9a982ac9b8b741",
+ component_id="8505ba55-ef72-629e-f85c-33e4b703d48b",
+ locale_id="65427cf400e02b306eaa04a0",
+ branch_id="68026fa68ef6dc744c75b833",
+ properties=[
+ ComponentPropertiesWritePropertiesItem(
+ property_id="a245c12d-995b-55ee-5ec7-aa36a6cad623",
+ text="The Hitchhiker’s Guide to the Galaxy",
+ ),
+ ComponentPropertiesWritePropertiesItem(
+ property_id="a245c12d-995b-55ee-5ec7-aa36a6cad627",
+ text="Dont Panic! Always know where your towel is.
",
+ ),
+ ],
+ )
+ """
+ _response = self._raw_client.update_properties(
+ site_id,
+ component_id,
+ properties=properties,
+ locale_id=locale_id,
+ branch_id=branch_id,
+ request_options=request_options,
+ )
+ return _response.data
+
+
+class AsyncComponentsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._raw_client = AsyncRawComponentsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawComponentsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawComponentsClient
+ """
+ return self._raw_client
+
+ async def list(
+ self,
+ site_id: str,
+ *,
+ branch_id: typing.Optional[str] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ComponentList:
+ """
+ List of all components for a site.
+
+ Required scope | `components:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ branch_id : typing.Optional[str]
+ Scope the operation to work on a specific branch.
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ComponentList
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.components.list(
+ site_id="580e63e98c9a982ac9b8b741",
+ branch_id="68026fa68ef6dc744c75b833",
+ limit=1,
+ offset=1,
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.list(
+ site_id, branch_id=branch_id, limit=limit, offset=offset, request_options=request_options
+ )
+ return _response.data
+
+ async def get_content(
+ self,
+ site_id: str,
+ component_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ branch_id: typing.Optional[str] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ComponentDom:
+ """
+ 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.
+
+ Required scope | `components:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ component_id : str
+ Unique identifier for a Component
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ branch_id : typing.Optional[str]
+ Scope the operation to work on a specific branch.
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ComponentDom
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.components.get_content(
+ site_id="580e63e98c9a982ac9b8b741",
+ component_id="8505ba55-ef72-629e-f85c-33e4b703d48b",
+ locale_id="65427cf400e02b306eaa04a0",
+ branch_id="68026fa68ef6dc744c75b833",
+ limit=1,
+ offset=1,
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.get_content(
+ site_id,
+ component_id,
+ locale_id=locale_id,
+ branch_id=branch_id,
+ limit=limit,
+ offset=offset,
+ request_options=request_options,
+ )
+ return _response.data
+
+ async def update_content(
+ self,
+ site_id: str,
+ component_id: str,
+ *,
+ nodes: typing.Sequence[ComponentDomWriteNodesItem],
+ locale_id: typing.Optional[str] = None,
+ branch_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ComponentsUpdateContentResponse:
+ """
+ This endpoint updates content within a component defintion for **secondary locales**. It supports updating up to 1000 nodes in a single request.
+
+ Before making updates:
+ 1. Use the [get component content](/data/reference/pages-and-components/components/get-content) endpoint to identify available content nodes and their types.
+ 2. If your component definition has a component instance nested within it, retrieve the nested component instance's properties that you'll override using the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint.
+ 3. DOM elements may include a `data-w-id` attribute. This attribute is used by Webflow to maintain custom attributes and links across locales. Always include the original `data-w-id` value in your update requests to ensure consistent behavior across all locales.
+
+
+ This endpoint is specifically for localizing component definitions. Ensure that the specified `localeId` is a valid **secondary locale** for the site otherwise the request will fail.
+
+
+ Required scope | `components:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ component_id : str
+ Unique identifier for a Component
+
+ nodes : typing.Sequence[ComponentDomWriteNodesItem]
+ List of DOM Nodes with the new content that will be updated in each node.
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ branch_id : typing.Optional[str]
+ Scope the operation to work on a specific branch.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ComponentsUpdateContentResponse
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import (
+ AsyncWebflow,
+ ComponentInstanceNodePropertyOverridesWrite,
+ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem,
+ Select,
+ SelectNodeWriteChoicesItem,
+ SubmitButtonNodeWrite,
+ TextInputNodeWrite,
+ TextNodeWrite,
+ )
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.components.update_content(
+ site_id="580e63e98c9a982ac9b8b741",
+ component_id="8505ba55-ef72-629e-f85c-33e4b703d48b",
+ locale_id="65427cf400e02b306eaa04a0",
+ branch_id="68026fa68ef6dc744c75b833",
+ nodes=[
+ TextNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad623",
+ text="The Hitchhiker's Guide to the Galaxy ",
+ ),
+ TextNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad627",
+ text="Don't Panic! Always know where your towel is.
",
+ ),
+ Select(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad635",
+ choices=[
+ SelectNodeWriteChoicesItem(
+ value="choice-1",
+ text="First choice",
+ ),
+ SelectNodeWriteChoicesItem(
+ value="choice-2",
+ text="Second choice",
+ ),
+ ],
+ ),
+ TextInputNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad642",
+ placeholder="Enter something here...",
+ ),
+ SubmitButtonNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad671",
+ value="Submit",
+ waiting_text="Submitting...",
+ ),
+ ComponentInstanceNodePropertyOverridesWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad629",
+ property_overrides=[
+ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem(
+ property_id="7dd14c08-2e96-8d3d-2b19-b5c03642a0f0",
+ text="
Time is an illusion ",
+ ),
+ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem(
+ property_id="7dd14c08-2e96-8d3d-2b19-b5c03642a0f1",
+ text="Life, the Universe and Everything",
+ ),
+ ],
+ ),
+ ],
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.update_content(
+ site_id,
+ component_id,
+ nodes=nodes,
+ locale_id=locale_id,
+ branch_id=branch_id,
+ request_options=request_options,
+ )
+ return _response.data
+
+ async def get_properties(
+ self,
+ site_id: str,
+ component_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ branch_id: typing.Optional[str] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ComponentProperties:
+ """
+ Get the default property values of a component definition.
+
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ component_id : str
+ Unique identifier for a Component
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ branch_id : typing.Optional[str]
+ Scope the operation to work on a specific branch.
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ComponentProperties
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.components.get_properties(
+ site_id="580e63e98c9a982ac9b8b741",
+ component_id="8505ba55-ef72-629e-f85c-33e4b703d48b",
+ locale_id="65427cf400e02b306eaa04a0",
+ branch_id="68026fa68ef6dc744c75b833",
+ limit=1,
+ offset=1,
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.get_properties(
+ site_id,
+ component_id,
+ locale_id=locale_id,
+ branch_id=branch_id,
+ limit=limit,
+ offset=offset,
+ request_options=request_options,
+ )
+ return _response.data
+
+ async def update_properties(
+ self,
+ site_id: str,
+ component_id: str,
+ *,
+ properties: typing.Sequence[ComponentPropertiesWritePropertiesItem],
+ locale_id: typing.Optional[str] = None,
+ branch_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ComponentsUpdatePropertiesResponse:
+ """
+ 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 properties that can be updated in a secondary locale.
+ 2. Rich Text properties may include a `data-w-id` attribute. This attribute is used by Webflow to maintain links across locales. Always include the original `data-w-id` value in your update requests to ensure consistent behavior across all locales.
+
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ component_id : str
+ Unique identifier for a Component
+
+ properties : typing.Sequence[ComponentPropertiesWritePropertiesItem]
+ A list of component properties to update within the specified secondary locale.
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ branch_id : typing.Optional[str]
+ Scope the operation to work on a specific branch.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ComponentsUpdatePropertiesResponse
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+ from webflow.resources.components import ComponentPropertiesWritePropertiesItem
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.components.update_properties(
+ site_id="580e63e98c9a982ac9b8b741",
+ component_id="8505ba55-ef72-629e-f85c-33e4b703d48b",
+ locale_id="65427cf400e02b306eaa04a0",
+ branch_id="68026fa68ef6dc744c75b833",
+ properties=[
+ ComponentPropertiesWritePropertiesItem(
+ property_id="a245c12d-995b-55ee-5ec7-aa36a6cad623",
+ text="The Hitchhiker’s Guide to the Galaxy",
+ ),
+ ComponentPropertiesWritePropertiesItem(
+ property_id="a245c12d-995b-55ee-5ec7-aa36a6cad627",
+ text="Dont Panic! Always know where your towel is.
",
+ ),
+ ],
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.update_properties(
+ site_id,
+ component_id,
+ properties=properties,
+ locale_id=locale_id,
+ branch_id=branch_id,
+ request_options=request_options,
+ )
+ return _response.data
diff --git a/src/webflow/resources/components/raw_client.py b/src/webflow/resources/components/raw_client.py
new file mode 100644
index 0000000..caf0799
--- /dev/null
+++ b/src/webflow/resources/components/raw_client.py
@@ -0,0 +1,1417 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from ...core.api_error import ApiError
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.http_response import AsyncHttpResponse, HttpResponse
+from ...core.jsonable_encoder import jsonable_encoder
+from ...core.parse_error import ParsingError
+from ...core.pydantic_utilities import parse_obj_as
+from ...core.request_options import RequestOptions
+from ...core.serialization import convert_and_respect_annotation_metadata
+from ...errors.bad_request_error import BadRequestError
+from ...errors.forbidden_error import ForbiddenError
+from ...errors.internal_server_error import InternalServerError
+from ...errors.not_found_error import NotFoundError
+from ...errors.too_many_requests_error import TooManyRequestsError
+from ...errors.unauthorized_error import UnauthorizedError
+from ...types.component_dom import ComponentDom
+from ...types.component_list import ComponentList
+from ...types.component_properties import ComponentProperties
+from ...types.error import Error
+from .types.component_dom_write_nodes_item import ComponentDomWriteNodesItem
+from .types.component_properties_write_properties_item import ComponentPropertiesWritePropertiesItem
+from .types.components_update_content_response import ComponentsUpdateContentResponse
+from .types.components_update_properties_response import ComponentsUpdatePropertiesResponse
+from pydantic import ValidationError
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RawComponentsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def list(
+ self,
+ site_id: str,
+ *,
+ branch_id: typing.Optional[str] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[ComponentList]:
+ """
+ List of all components for a site.
+
+ Required scope | `components:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ branch_id : typing.Optional[str]
+ Scope the operation to work on a specific branch.
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[ComponentList]
+ Request was successful
+ """
+ _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={
+ "branchId": branch_id,
+ "limit": limit,
+ "offset": offset,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ComponentList,
+ parse_obj_as(
+ type_=ComponentList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def get_content(
+ self,
+ site_id: str,
+ component_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ branch_id: typing.Optional[str] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[ComponentDom]:
+ """
+ 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.
+
+ Required scope | `components:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ component_id : str
+ Unique identifier for a Component
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ branch_id : typing.Optional[str]
+ Scope the operation to work on a specific branch.
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[ComponentDom]
+ Request was successful
+ """
+ _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,
+ "branchId": branch_id,
+ "limit": limit,
+ "offset": offset,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ComponentDom,
+ parse_obj_as(
+ type_=ComponentDom, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def update_content(
+ self,
+ site_id: str,
+ component_id: str,
+ *,
+ nodes: typing.Sequence[ComponentDomWriteNodesItem],
+ locale_id: typing.Optional[str] = None,
+ branch_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[ComponentsUpdateContentResponse]:
+ """
+ This endpoint updates content within a component defintion for **secondary locales**. It supports updating up to 1000 nodes in a single request.
+
+ Before making updates:
+ 1. Use the [get component content](/data/reference/pages-and-components/components/get-content) endpoint to identify available content nodes and their types.
+ 2. If your component definition has a component instance nested within it, retrieve the nested component instance's properties that you'll override using the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint.
+ 3. DOM elements may include a `data-w-id` attribute. This attribute is used by Webflow to maintain custom attributes and links across locales. Always include the original `data-w-id` value in your update requests to ensure consistent behavior across all locales.
+
+
+ This endpoint is specifically for localizing component definitions. Ensure that the specified `localeId` is a valid **secondary locale** for the site otherwise the request will fail.
+
+
+ Required scope | `components:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ component_id : str
+ Unique identifier for a Component
+
+ nodes : typing.Sequence[ComponentDomWriteNodesItem]
+ List of DOM Nodes with the new content that will be updated in each node.
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ branch_id : typing.Optional[str]
+ Scope the operation to work on a specific branch.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[ComponentsUpdateContentResponse]
+ Request was successful
+ """
+ _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,
+ "branchId": branch_id,
+ },
+ json={
+ "nodes": convert_and_respect_annotation_metadata(
+ object_=nodes, annotation=typing.Sequence[ComponentDomWriteNodesItem], direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ComponentsUpdateContentResponse,
+ parse_obj_as(
+ type_=ComponentsUpdateContentResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def get_properties(
+ self,
+ site_id: str,
+ component_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ branch_id: typing.Optional[str] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[ComponentProperties]:
+ """
+ Get the default property values of a component definition.
+
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ component_id : str
+ Unique identifier for a Component
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ branch_id : typing.Optional[str]
+ Scope the operation to work on a specific branch.
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[ComponentProperties]
+ Request was successful
+ """
+ _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,
+ "branchId": branch_id,
+ "limit": limit,
+ "offset": offset,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ComponentProperties,
+ parse_obj_as(
+ type_=ComponentProperties, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def update_properties(
+ self,
+ site_id: str,
+ component_id: str,
+ *,
+ properties: typing.Sequence[ComponentPropertiesWritePropertiesItem],
+ locale_id: typing.Optional[str] = None,
+ branch_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[ComponentsUpdatePropertiesResponse]:
+ """
+ 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 properties that can be updated in a secondary locale.
+ 2. Rich Text properties may include a `data-w-id` attribute. This attribute is used by Webflow to maintain links across locales. Always include the original `data-w-id` value in your update requests to ensure consistent behavior across all locales.
+
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ component_id : str
+ Unique identifier for a Component
+
+ properties : typing.Sequence[ComponentPropertiesWritePropertiesItem]
+ A list of component properties to update within the specified secondary locale.
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ branch_id : typing.Optional[str]
+ Scope the operation to work on a specific branch.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[ComponentsUpdatePropertiesResponse]
+ Request was successful
+ """
+ _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,
+ "branchId": branch_id,
+ },
+ json={
+ "properties": convert_and_respect_annotation_metadata(
+ object_=properties,
+ annotation=typing.Sequence[ComponentPropertiesWritePropertiesItem],
+ direction="write",
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ComponentsUpdatePropertiesResponse,
+ parse_obj_as(
+ type_=ComponentsUpdatePropertiesResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawComponentsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def list(
+ self,
+ site_id: str,
+ *,
+ branch_id: typing.Optional[str] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[ComponentList]:
+ """
+ List of all components for a site.
+
+ Required scope | `components:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ branch_id : typing.Optional[str]
+ Scope the operation to work on a specific branch.
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[ComponentList]
+ Request was successful
+ """
+ _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={
+ "branchId": branch_id,
+ "limit": limit,
+ "offset": offset,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ComponentList,
+ parse_obj_as(
+ type_=ComponentList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def get_content(
+ self,
+ site_id: str,
+ component_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ branch_id: typing.Optional[str] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[ComponentDom]:
+ """
+ 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.
+
+ Required scope | `components:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ component_id : str
+ Unique identifier for a Component
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ branch_id : typing.Optional[str]
+ Scope the operation to work on a specific branch.
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[ComponentDom]
+ Request was successful
+ """
+ _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,
+ "branchId": branch_id,
+ "limit": limit,
+ "offset": offset,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ComponentDom,
+ parse_obj_as(
+ type_=ComponentDom, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def update_content(
+ self,
+ site_id: str,
+ component_id: str,
+ *,
+ nodes: typing.Sequence[ComponentDomWriteNodesItem],
+ locale_id: typing.Optional[str] = None,
+ branch_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[ComponentsUpdateContentResponse]:
+ """
+ This endpoint updates content within a component defintion for **secondary locales**. It supports updating up to 1000 nodes in a single request.
+
+ Before making updates:
+ 1. Use the [get component content](/data/reference/pages-and-components/components/get-content) endpoint to identify available content nodes and their types.
+ 2. If your component definition has a component instance nested within it, retrieve the nested component instance's properties that you'll override using the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint.
+ 3. DOM elements may include a `data-w-id` attribute. This attribute is used by Webflow to maintain custom attributes and links across locales. Always include the original `data-w-id` value in your update requests to ensure consistent behavior across all locales.
+
+
+ This endpoint is specifically for localizing component definitions. Ensure that the specified `localeId` is a valid **secondary locale** for the site otherwise the request will fail.
+
+
+ Required scope | `components:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ component_id : str
+ Unique identifier for a Component
+
+ nodes : typing.Sequence[ComponentDomWriteNodesItem]
+ List of DOM Nodes with the new content that will be updated in each node.
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ branch_id : typing.Optional[str]
+ Scope the operation to work on a specific branch.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[ComponentsUpdateContentResponse]
+ Request was successful
+ """
+ _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,
+ "branchId": branch_id,
+ },
+ json={
+ "nodes": convert_and_respect_annotation_metadata(
+ object_=nodes, annotation=typing.Sequence[ComponentDomWriteNodesItem], direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ComponentsUpdateContentResponse,
+ parse_obj_as(
+ type_=ComponentsUpdateContentResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def get_properties(
+ self,
+ site_id: str,
+ component_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ branch_id: typing.Optional[str] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[ComponentProperties]:
+ """
+ Get the default property values of a component definition.
+
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ component_id : str
+ Unique identifier for a Component
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ branch_id : typing.Optional[str]
+ Scope the operation to work on a specific branch.
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[ComponentProperties]
+ Request was successful
+ """
+ _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,
+ "branchId": branch_id,
+ "limit": limit,
+ "offset": offset,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ComponentProperties,
+ parse_obj_as(
+ type_=ComponentProperties, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def update_properties(
+ self,
+ site_id: str,
+ component_id: str,
+ *,
+ properties: typing.Sequence[ComponentPropertiesWritePropertiesItem],
+ locale_id: typing.Optional[str] = None,
+ branch_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[ComponentsUpdatePropertiesResponse]:
+ """
+ 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 properties that can be updated in a secondary locale.
+ 2. Rich Text properties may include a `data-w-id` attribute. This attribute is used by Webflow to maintain links across locales. Always include the original `data-w-id` value in your update requests to ensure consistent behavior across all locales.
+
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ component_id : str
+ Unique identifier for a Component
+
+ properties : typing.Sequence[ComponentPropertiesWritePropertiesItem]
+ A list of component properties to update within the specified secondary locale.
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ branch_id : typing.Optional[str]
+ Scope the operation to work on a specific branch.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[ComponentsUpdatePropertiesResponse]
+ Request was successful
+ """
+ _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,
+ "branchId": branch_id,
+ },
+ json={
+ "properties": convert_and_respect_annotation_metadata(
+ object_=properties,
+ annotation=typing.Sequence[ComponentPropertiesWritePropertiesItem],
+ direction="write",
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ComponentsUpdatePropertiesResponse,
+ parse_obj_as(
+ type_=ComponentsUpdatePropertiesResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/components/types/__init__.py b/src/webflow/resources/components/types/__init__.py
new file mode 100644
index 0000000..d3d0a32
--- /dev/null
+++ b/src/webflow/resources/components/types/__init__.py
@@ -0,0 +1,47 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .component_dom_write_nodes_item import ComponentDomWriteNodesItem
+ from .component_properties_write_properties_item import ComponentPropertiesWritePropertiesItem
+ from .components_update_content_response import ComponentsUpdateContentResponse
+ from .components_update_properties_response import ComponentsUpdatePropertiesResponse
+_dynamic_imports: typing.Dict[str, str] = {
+ "ComponentDomWriteNodesItem": ".component_dom_write_nodes_item",
+ "ComponentPropertiesWritePropertiesItem": ".component_properties_write_properties_item",
+ "ComponentsUpdateContentResponse": ".components_update_content_response",
+ "ComponentsUpdatePropertiesResponse": ".components_update_properties_response",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = [
+ "ComponentDomWriteNodesItem",
+ "ComponentPropertiesWritePropertiesItem",
+ "ComponentsUpdateContentResponse",
+ "ComponentsUpdatePropertiesResponse",
+]
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
new file mode 100644
index 0000000..8bb5e53
--- /dev/null
+++ b/src/webflow/resources/components/types/component_dom_write_nodes_item.py
@@ -0,0 +1,19 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from ....types.component_instance_node_property_overrides_write import ComponentInstanceNodePropertyOverridesWrite
+from ....types.search_button_node_write import SearchButtonNodeWrite
+from ....types.select import Select
+from ....types.submit_button_node_write import SubmitButtonNodeWrite
+from ....types.text_input_node_write import TextInputNodeWrite
+from ....types.text_node_write import TextNodeWrite
+
+ComponentDomWriteNodesItem = typing.Union[
+ TextNodeWrite,
+ ComponentInstanceNodePropertyOverridesWrite,
+ Select,
+ TextInputNodeWrite,
+ SubmitButtonNodeWrite,
+ SearchButtonNodeWrite,
+]
diff --git a/src/webflow/resources/components/types/component_properties_write_properties_item.py b/src/webflow/resources/components/types/component_properties_write_properties_item.py
new file mode 100644
index 0000000..30da057
--- /dev/null
+++ b/src/webflow/resources/components/types/component_properties_write_properties_item.py
@@ -0,0 +1,34 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ....core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ....core.serialization import FieldMetadata
+
+
+class ComponentPropertiesWritePropertiesItem(UniversalBaseModel):
+ property_id: typing_extensions.Annotated[
+ str,
+ FieldMetadata(alias="propertyId"),
+ pydantic.Field(alias="propertyId", description="The ID of the property."),
+ ]
+ text: str = pydantic.Field()
+ """
+ The new string or HTML value used to update the component property in the secondary locale.
+
+ The provided value must be compatible with the type of the component property.
+
+ For example, attempting to update a single-line plain-text property with a multi-line
+ value will result in an error.
+ """
+
+ 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/components/types/components_update_content_response.py b/src/webflow/resources/components/types/components_update_content_response.py
new file mode 100644
index 0000000..9021766
--- /dev/null
+++ b/src/webflow/resources/components/types/components_update_content_response.py
@@ -0,0 +1,22 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ....core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class ComponentsUpdateContentResponse(UniversalBaseModel):
+ errors: typing.List[str] = pydantic.Field()
+ """
+ A list of error messages, if any.
+ """
+
+ 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/components/types/components_update_properties_response.py b/src/webflow/resources/components/types/components_update_properties_response.py
new file mode 100644
index 0000000..7dffd8b
--- /dev/null
+++ b/src/webflow/resources/components/types/components_update_properties_response.py
@@ -0,0 +1,22 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ....core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class ComponentsUpdatePropertiesResponse(UniversalBaseModel):
+ errors: typing.List[str] = pydantic.Field()
+ """
+ A list of error messages, if any.
+ """
+
+ 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/ecommerce/__init__.py b/src/webflow/resources/ecommerce/__init__.py
index f3ea265..5cde020 100644
--- a/src/webflow/resources/ecommerce/__init__.py
+++ b/src/webflow/resources/ecommerce/__init__.py
@@ -1,2 +1,4 @@
# This file was auto-generated by Fern from our API Definition.
+# isort: skip_file
+
diff --git a/src/webflow/resources/ecommerce/client.py b/src/webflow/resources/ecommerce/client.py
index d1d7129..e62f87b 100644
--- a/src/webflow/resources/ecommerce/client.py
+++ b/src/webflow/resources/ecommerce/client.py
@@ -1,32 +1,27 @@
# This file was auto-generated by Fern from our API Definition.
import typing
-import urllib.parse
-from json.decoder import JSONDecodeError
-from ...core.api_error import ApiError
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from ...core.jsonable_encoder import jsonable_encoder
-from ...core.remove_none_from_dict import remove_none_from_dict
from ...core.request_options import RequestOptions
-from ...errors.bad_request_error import BadRequestError
-from ...errors.conflict_error import ConflictError
-from ...errors.forbidden_error import ForbiddenError
-from ...errors.internal_server_error import InternalServerError
-from ...errors.not_found_error import NotFoundError
-from ...errors.too_many_requests_error import TooManyRequestsError
-from ...errors.unauthorized_error import UnauthorizedError
from ...types.ecommerce_settings import EcommerceSettings
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+from .raw_client import AsyncRawEcommerceClient, RawEcommerceClient
class EcommerceClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = RawEcommerceClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawEcommerceClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawEcommerceClient
+ """
+ return self._raw_client
def get_settings(
self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
@@ -36,66 +31,48 @@ def get_settings(
Required scope | `ecommerce:read`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Returns
+ -------
+ EcommerceSettings
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.ecommerce.get_settings(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/ecommerce/settings"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(EcommerceSettings, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.get_settings(site_id, request_options=request_options)
+ return _response.data
class AsyncEcommerceClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = AsyncRawEcommerceClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawEcommerceClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawEcommerceClient
+ """
+ return self._raw_client
async def get_settings(
self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
@@ -105,58 +82,37 @@ async def get_settings(
Required scope | `ecommerce:read`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ EcommerceSettings
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.ecommerce.get_settings(
- site_id="site_id",
- )
+
+
+ async def main() -> None:
+ await client.ecommerce.get_settings(
+ site_id="580e63e98c9a982ac9b8b741",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/ecommerce/settings"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(EcommerceSettings, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.get_settings(site_id, request_options=request_options)
+ return _response.data
diff --git a/src/webflow/resources/ecommerce/raw_client.py b/src/webflow/resources/ecommerce/raw_client.py
new file mode 100644
index 0000000..4aa1da3
--- /dev/null
+++ b/src/webflow/resources/ecommerce/raw_client.py
@@ -0,0 +1,278 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from ...core.api_error import ApiError
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.http_response import AsyncHttpResponse, HttpResponse
+from ...core.jsonable_encoder import jsonable_encoder
+from ...core.parse_error import ParsingError
+from ...core.pydantic_utilities import parse_obj_as
+from ...core.request_options import RequestOptions
+from ...errors.bad_request_error import BadRequestError
+from ...errors.conflict_error import ConflictError
+from ...errors.forbidden_error import ForbiddenError
+from ...errors.internal_server_error import InternalServerError
+from ...errors.not_found_error import NotFoundError
+from ...errors.too_many_requests_error import TooManyRequestsError
+from ...errors.unauthorized_error import UnauthorizedError
+from ...types.ecommerce_settings import EcommerceSettings
+from ...types.error import Error
+from pydantic import ValidationError
+
+
+class RawEcommerceClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def get_settings(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[EcommerceSettings]:
+ """
+ Retrieve ecommerce settings for a site.
+
+ Required scope | `ecommerce:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[EcommerceSettings]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ EcommerceSettings,
+ parse_obj_as(
+ type_=EcommerceSettings, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawEcommerceClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def get_settings(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[EcommerceSettings]:
+ """
+ Retrieve ecommerce settings for a site.
+
+ Required scope | `ecommerce:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[EcommerceSettings]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ EcommerceSettings,
+ parse_obj_as(
+ type_=EcommerceSettings, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/forms/__init__.py b/src/webflow/resources/forms/__init__.py
index f3ea265..5cde020 100644
--- a/src/webflow/resources/forms/__init__.py
+++ b/src/webflow/resources/forms/__init__.py
@@ -1,2 +1,4 @@
# This file was auto-generated by Fern from our API Definition.
+# isort: skip_file
+
diff --git a/src/webflow/resources/forms/client.py b/src/webflow/resources/forms/client.py
index e186f96..f49ab25 100644
--- a/src/webflow/resources/forms/client.py
+++ b/src/webflow/resources/forms/client.py
@@ -1,30 +1,14 @@
# This file was auto-generated by Fern from our API Definition.
import typing
-import urllib.parse
-from json.decoder import JSONDecodeError
-from ...core.api_error import ApiError
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from ...core.jsonable_encoder import jsonable_encoder
-from ...core.remove_none_from_dict import remove_none_from_dict
from ...core.request_options import RequestOptions
-from ...errors.bad_request_error import BadRequestError
-from ...errors.conflict_error import ConflictError
-from ...errors.forbidden_error import ForbiddenError
-from ...errors.internal_server_error import InternalServerError
-from ...errors.not_found_error import NotFoundError
-from ...errors.too_many_requests_error import TooManyRequestsError
-from ...errors.unauthorized_error import UnauthorizedError
from ...types.form import Form
from ...types.form_list import FormList
from ...types.form_submission import FormSubmission
from ...types.form_submission_list import FormSubmissionList
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+from .raw_client import AsyncRawFormsClient, RawFormsClient
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
@@ -32,262 +16,225 @@
class FormsClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = RawFormsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawFormsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawFormsClient
+ """
+ return self._raw_client
def list(
self,
site_id: str,
*,
- limit: typing.Optional[float] = None,
- offset: typing.Optional[float] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> FormList:
"""
- List forms for a given site Required scope | `forms:read`
+ List forms for a given site.
+
+ Required scope | `forms:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
- Parameters:
- - site_id: str. Unique identifier for a Site
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
- - limit: typing.Optional[float]. Maximum number of records to be returned (max limit: 100)
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - offset: typing.Optional[float]. Offset used for pagination if the results have more than limit records
+ Returns
+ -------
+ FormList
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.forms.list(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
+ limit=1,
+ offset=1,
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/forms"),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "limit": limit,
- "offset": offset,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(FormList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.list(site_id, limit=limit, offset=offset, request_options=request_options)
+ return _response.data
def get(self, form_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Form:
"""
- Get information about a given form Required scope | `forms:read`
+ Get information about a given form.
+
+ Required scope | `forms:read`
+
+ Parameters
+ ----------
+ form_id : str
+ Unique identifier for a Form
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- Parameters:
- - form_id: str. Unique identifier for a Form
+ Returns
+ -------
+ Form
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.forms.get(
- form_id="form_id",
+ form_id="580e63e98c9a982ac9b8b741",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"forms/{jsonable_encoder(form_id)}"),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Form, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.get(form_id, request_options=request_options)
+ return _response.data
def list_submissions(
- self, form_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ self,
+ form_id: str,
+ *,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
) -> FormSubmissionList:
"""
- List form submissions for a given form Required scope | `forms:read`
+ 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
+ ----------
+ form_id : str
+ Unique identifier for a Form
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- Parameters:
- - form_id: str. Unique identifier for a Form
+ Returns
+ -------
+ FormSubmissionList
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.forms.list_submissions(
- form_id="form_id",
+ form_id="580e63e98c9a982ac9b8b741",
+ offset=1,
+ limit=1,
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"forms/{jsonable_encoder(form_id)}/submissions"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.list_submissions(
+ form_id, offset=offset, limit=limit, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(FormSubmissionList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
def get_submission(
self, form_submission_id: str, *, request_options: typing.Optional[RequestOptions] = None
) -> FormSubmission:
"""
- Get information about a given form submission Required scope | `forms:read`
+ Get information about a given form submissio.
- Parameters:
- - form_submission_id: str. Unique identifier for a Form Submission
+ Required scope | `forms:read`
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Parameters
+ ----------
+ form_submission_id : str
+ Unique identifier for a Form Submission
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ FormSubmission
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.forms.get_submission(
- form_submission_id="form_submission_id",
+ form_submission_id="580e63e98c9a982ac9b8b741",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"form_submissions/{jsonable_encoder(form_submission_id)}"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.get_submission(form_submission_id, request_options=request_options)
+ return _response.data
+
+ 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",
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(FormSubmission, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ client.forms.delete_submission(
+ form_submission_id="580e63e98c9a982ac9b8b741",
+ )
+ """
+ _response = self._raw_client.delete_submission(form_submission_id, request_options=request_options)
+ return _response.data
def update_submission(
self,
@@ -297,334 +244,304 @@ def update_submission(
request_options: typing.Optional[RequestOptions] = None,
) -> FormSubmission:
"""
- Update hidden fields on a form submission Required scope | `forms:write`
+ Update hidden fields on a form submission
+
+ Required scope | `forms:write`
+
+ Parameters
+ ----------
+ form_submission_id : str
+ Unique identifier for a Form Submission
- Parameters:
- - form_submission_id: str. Unique identifier for a Form Submission
+ form_submission_data : typing.Optional[typing.Dict[str, typing.Any]]
+ An existing **hidden field** defined on the form schema, and the corresponding value to set
- - form_submission_data: typing.Optional[typing.Dict[str, typing.Any]]. An existing **hidden field** defined on the form schema, and the corresponding value to set
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Returns
+ -------
+ FormSubmission
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.forms.update_submission(
- form_submission_id="form_submission_id",
+ form_submission_id="580e63e98c9a982ac9b8b741",
)
"""
- _request: typing.Dict[str, typing.Any] = {}
- if form_submission_data is not OMIT:
- _request["formSubmissionData"] = form_submission_data
- _response = self._client_wrapper.httpx_client.request(
- "PATCH",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"form_submissions/{jsonable_encoder(form_submission_id)}"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.update_submission(
+ form_submission_id, form_submission_data=form_submission_data, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(FormSubmission, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
class AsyncFormsClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = AsyncRawFormsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawFormsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawFormsClient
+ """
+ return self._raw_client
async def list(
self,
site_id: str,
*,
- limit: typing.Optional[float] = None,
- offset: typing.Optional[float] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> FormList:
"""
- List forms for a given site Required scope | `forms:read`
+ List forms for a given site.
+
+ Required scope | `forms:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- Parameters:
- - site_id: str. Unique identifier for a Site
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
- - limit: typing.Optional[float]. Maximum number of records to be returned (max limit: 100)
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
- - offset: typing.Optional[float]. Offset used for pagination if the results have more than limit records
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Returns
+ -------
+ FormList
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.forms.list(
- site_id="site_id",
- )
+
+
+ async def main() -> None:
+ await client.forms.list(
+ site_id="580e63e98c9a982ac9b8b741",
+ limit=1,
+ offset=1,
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/forms"),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "limit": limit,
- "offset": offset,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(FormList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.list(site_id, limit=limit, offset=offset, request_options=request_options)
+ return _response.data
async def get(self, form_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Form:
"""
- Get information about a given form Required scope | `forms:read`
+ Get information about a given form.
+
+ Required scope | `forms:read`
+
+ Parameters
+ ----------
+ form_id : str
+ Unique identifier for a Form
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- Parameters:
- - form_id: str. Unique identifier for a Form
+ Returns
+ -------
+ Form
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.forms.get(
- form_id="form_id",
- )
+
+
+ async def main() -> None:
+ await client.forms.get(
+ form_id="580e63e98c9a982ac9b8b741",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"forms/{jsonable_encoder(form_id)}"),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Form, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.get(form_id, request_options=request_options)
+ return _response.data
async def list_submissions(
- self, form_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ self,
+ form_id: str,
+ *,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
) -> FormSubmissionList:
"""
- List form submissions for a given form Required scope | `forms:read`
+ 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
+ ----------
+ form_id : str
+ Unique identifier for a Form
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
- Parameters:
- - form_id: str. Unique identifier for a Form
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ 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",
)
- await client.forms.list_submissions(
- form_id="form_id",
- )
+
+
+ async def main() -> None:
+ await client.forms.list_submissions(
+ form_id="580e63e98c9a982ac9b8b741",
+ offset=1,
+ limit=1,
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"forms/{jsonable_encoder(form_id)}/submissions"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.list_submissions(
+ form_id, offset=offset, limit=limit, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(FormSubmissionList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
async def get_submission(
self, form_submission_id: str, *, request_options: typing.Optional[RequestOptions] = None
) -> FormSubmission:
"""
- Get information about a given form submission Required scope | `forms:read`
+ Get information about a given form submissio.
- Parameters:
- - form_submission_id: str. Unique identifier for a Form Submission
+ Required scope | `forms:read`
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Parameters
+ ----------
+ form_submission_id : str
+ Unique identifier for a Form Submission
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ FormSubmission
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.forms.get_submission(
- form_submission_id="form_submission_id",
- )
+
+
+ async def main() -> None:
+ await client.forms.get_submission(
+ form_submission_id="580e63e98c9a982ac9b8b741",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.get_submission(form_submission_id, request_options=request_options)
+ return _response.data
+
+ async def delete_submission(
+ self, form_submission_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> None:
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"form_submissions/{jsonable_encoder(form_submission_id)}"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ 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",
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(FormSubmission, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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 main() -> None:
+ await client.forms.delete_submission(
+ form_submission_id="580e63e98c9a982ac9b8b741",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.delete_submission(form_submission_id, request_options=request_options)
+ return _response.data
async def update_submission(
self,
@@ -634,71 +551,46 @@ async def update_submission(
request_options: typing.Optional[RequestOptions] = None,
) -> FormSubmission:
"""
- Update hidden fields on a form submission Required scope | `forms:write`
+ Update hidden fields on a form submission
+
+ Required scope | `forms:write`
+
+ Parameters
+ ----------
+ form_submission_id : str
+ Unique identifier for a Form Submission
- Parameters:
- - form_submission_id: str. Unique identifier for a Form Submission
+ form_submission_data : typing.Optional[typing.Dict[str, typing.Any]]
+ An existing **hidden field** defined on the form schema, and the corresponding value to set
- - form_submission_data: typing.Optional[typing.Dict[str, typing.Any]]. An existing **hidden field** defined on the form schema, and the corresponding value to set
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Returns
+ -------
+ FormSubmission
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.forms.update_submission(
- form_submission_id="form_submission_id",
- )
+
+
+ async def main() -> None:
+ await client.forms.update_submission(
+ form_submission_id="580e63e98c9a982ac9b8b741",
+ )
+
+
+ asyncio.run(main())
"""
- _request: typing.Dict[str, typing.Any] = {}
- if form_submission_data is not OMIT:
- _request["formSubmissionData"] = form_submission_data
- _response = await self._client_wrapper.httpx_client.request(
- "PATCH",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"form_submissions/{jsonable_encoder(form_submission_id)}"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.update_submission(
+ form_submission_id, form_submission_data=form_submission_data, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(FormSubmission, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
diff --git a/src/webflow/resources/forms/raw_client.py b/src/webflow/resources/forms/raw_client.py
new file mode 100644
index 0000000..aa85c4e
--- /dev/null
+++ b/src/webflow/resources/forms/raw_client.py
@@ -0,0 +1,1532 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from ...core.api_error import ApiError
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.http_response import AsyncHttpResponse, HttpResponse
+from ...core.jsonable_encoder import jsonable_encoder
+from ...core.parse_error import ParsingError
+from ...core.pydantic_utilities import parse_obj_as
+from ...core.request_options import RequestOptions
+from ...errors.bad_request_error import BadRequestError
+from ...errors.conflict_error import ConflictError
+from ...errors.forbidden_error import ForbiddenError
+from ...errors.internal_server_error import InternalServerError
+from ...errors.not_found_error import NotFoundError
+from ...errors.too_many_requests_error import TooManyRequestsError
+from ...errors.unauthorized_error import UnauthorizedError
+from ...types.error import Error
+from ...types.form import Form
+from ...types.form_list import FormList
+from ...types.form_submission import FormSubmission
+from ...types.form_submission_list import FormSubmissionList
+from pydantic import ValidationError
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RawFormsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def list(
+ self,
+ site_id: str,
+ *,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[FormList]:
+ """
+ List forms for a given site.
+
+ Required scope | `forms:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[FormList]
+ Request was successful
+ """
+ _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,
+ "offset": offset,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ FormList,
+ parse_obj_as(
+ type_=FormList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def get(self, form_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[Form]:
+ """
+ Get information about a given form.
+
+ Required scope | `forms:read`
+
+ Parameters
+ ----------
+ form_id : str
+ Unique identifier for a Form
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Form]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Form,
+ parse_obj_as(
+ type_=Form, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def list_submissions(
+ self,
+ form_id: str,
+ *,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[FormSubmissionList]:
+ """
+ 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
+ ----------
+ form_id : str
+ Unique identifier for a Form
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[FormSubmissionList]
+ Request was successful
+ """
+ _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,
+ "limit": limit,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ FormSubmissionList,
+ parse_obj_as(
+ type_=FormSubmissionList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def get_submission(
+ self, form_submission_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[FormSubmission]:
+ """
+ Get information about a given form submissio.
+
+ Required scope | `forms:read`
+
+ Parameters
+ ----------
+ form_submission_id : str
+ Unique identifier for a Form Submission
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[FormSubmission]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ FormSubmission,
+ parse_obj_as(
+ type_=FormSubmission, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def delete_submission(
+ self, form_submission_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[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
+ -------
+ HttpResponse[None]
+ """
+ _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 HttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def update_submission(
+ self,
+ form_submission_id: str,
+ *,
+ form_submission_data: typing.Optional[typing.Dict[str, typing.Any]] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[FormSubmission]:
+ """
+ Update hidden fields on a form submission
+
+ Required scope | `forms:write`
+
+ Parameters
+ ----------
+ form_submission_id : str
+ Unique identifier for a Form Submission
+
+ form_submission_data : typing.Optional[typing.Dict[str, typing.Any]]
+ An existing **hidden field** defined on the form schema, and the corresponding value to set
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[FormSubmission]
+ Request was successful
+ """
+ _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,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ FormSubmission,
+ parse_obj_as(
+ type_=FormSubmission, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawFormsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def list(
+ self,
+ site_id: str,
+ *,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[FormList]:
+ """
+ List forms for a given site.
+
+ Required scope | `forms:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[FormList]
+ Request was successful
+ """
+ _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,
+ "offset": offset,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ FormList,
+ parse_obj_as(
+ type_=FormList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def get(
+ self, form_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[Form]:
+ """
+ Get information about a given form.
+
+ Required scope | `forms:read`
+
+ Parameters
+ ----------
+ form_id : str
+ Unique identifier for a Form
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Form]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Form,
+ parse_obj_as(
+ type_=Form, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def list_submissions(
+ self,
+ form_id: str,
+ *,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[FormSubmissionList]:
+ """
+ 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
+ ----------
+ form_id : str
+ Unique identifier for a Form
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[FormSubmissionList]
+ Request was successful
+ """
+ _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,
+ "limit": limit,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ FormSubmissionList,
+ parse_obj_as(
+ type_=FormSubmissionList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def get_submission(
+ self, form_submission_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[FormSubmission]:
+ """
+ Get information about a given form submissio.
+
+ Required scope | `forms:read`
+
+ Parameters
+ ----------
+ form_submission_id : str
+ Unique identifier for a Form Submission
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[FormSubmission]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ FormSubmission,
+ parse_obj_as(
+ type_=FormSubmission, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def delete_submission(
+ self, form_submission_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[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
+ -------
+ AsyncHttpResponse[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="DELETE",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return AsyncHttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def update_submission(
+ self,
+ form_submission_id: str,
+ *,
+ form_submission_data: typing.Optional[typing.Dict[str, typing.Any]] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[FormSubmission]:
+ """
+ Update hidden fields on a form submission
+
+ Required scope | `forms:write`
+
+ Parameters
+ ----------
+ form_submission_id : str
+ Unique identifier for a Form Submission
+
+ form_submission_data : typing.Optional[typing.Dict[str, typing.Any]]
+ An existing **hidden field** defined on the form schema, and the corresponding value to set
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[FormSubmission]
+ Request was successful
+ """
+ _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,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ FormSubmission,
+ parse_obj_as(
+ type_=FormSubmission, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/inventory/__init__.py b/src/webflow/resources/inventory/__init__.py
index f95deee..018e6a1 100644
--- a/src/webflow/resources/inventory/__init__.py
+++ b/src/webflow/resources/inventory/__init__.py
@@ -1,5 +1,37 @@
# This file was auto-generated by Fern from our API Definition.
-from .types import InventoryUpdateRequestInventoryType
+# isort: skip_file
-__all__ = ["InventoryUpdateRequestInventoryType"]
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .types import EcommInventoryChangedPayload, InventoryUpdateRequestInventoryType
+_dynamic_imports: typing.Dict[str, str] = {
+ "EcommInventoryChangedPayload": ".types",
+ "InventoryUpdateRequestInventoryType": ".types",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = ["EcommInventoryChangedPayload", "InventoryUpdateRequestInventoryType"]
diff --git a/src/webflow/resources/inventory/client.py b/src/webflow/resources/inventory/client.py
index 9b9589a..51c9454 100644
--- a/src/webflow/resources/inventory/client.py
+++ b/src/webflow/resources/inventory/client.py
@@ -1,109 +1,75 @@
# This file was auto-generated by Fern from our API Definition.
import typing
-import urllib.parse
-from json.decoder import JSONDecodeError
-from ...core.api_error import ApiError
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from ...core.jsonable_encoder import jsonable_encoder
-from ...core.remove_none_from_dict import remove_none_from_dict
from ...core.request_options import RequestOptions
-from ...errors.bad_request_error import BadRequestError
-from ...errors.conflict_error import ConflictError
-from ...errors.forbidden_error import ForbiddenError
-from ...errors.internal_server_error import InternalServerError
-from ...errors.not_found_error import NotFoundError
-from ...errors.too_many_requests_error import TooManyRequestsError
-from ...errors.unauthorized_error import UnauthorizedError
from ...types.inventory_item import InventoryItem
+from .raw_client import AsyncRawInventoryClient, RawInventoryClient
from .types.inventory_update_request_inventory_type import InventoryUpdateRequestInventoryType
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
class InventoryClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = RawInventoryClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawInventoryClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawInventoryClient
+ """
+ return self._raw_client
def list(
- self, collection_id: str, item_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ self, sku_collection_id: str, sku_id: str, *, request_options: typing.Optional[RequestOptions] = None
) -> InventoryItem:
"""
List the current inventory levels for a particular SKU item.
Required scope | `ecommerce:read`
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ Parameters
+ ----------
+ sku_collection_id : str
+ Unique identifier for a SKU collection. Use the List Collections API to find this ID.
- - item_id: str. Unique identifier for an Item
+ sku_id : str
+ Unique identifier for a SKU
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ InventoryItem
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.inventory.list(
- collection_id="collection_id",
- item_id="item_id",
+ sku_collection_id="6377a7c4b7a79608c34a46f7",
+ sku_id="5e8518516e147040726cc415",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/inventory",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(InventoryItem, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.list(sku_collection_id, sku_id, request_options=request_options)
+ return _response.data
def update(
self,
- collection_id: str,
- item_id: str,
+ sku_collection_id: str,
+ sku_id: str,
*,
inventory_type: InventoryUpdateRequestInventoryType,
update_quantity: typing.Optional[float] = OMIT,
@@ -111,168 +77,129 @@ def update(
request_options: typing.Optional[RequestOptions] = None,
) -> InventoryItem:
"""
- Updates the current inventory levels for a particular SKU item. Updates may be given in one or two methods, absolutely or incrementally. Absolute updates are done by setting `quantity` directly. Incremental updates are by specifying the inventory delta in `updateQuantity` which is then added to the `quantity` stored on the server.
+ Updates the current inventory levels for a particular SKU item.
+
+ Updates may be given in one or two methods, absolutely or incrementally.
+ - Absolute updates are done by setting `quantity` directly.
+ - Incremental updates are by specifying the inventory delta in `updateQuantity` which is then added to the `quantity` stored on the server.
Required scope | `ecommerce:write`
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ Parameters
+ ----------
+ sku_collection_id : str
+ Unique identifier for a SKU collection. Use the List Collections API to find this ID.
- - item_id: str. Unique identifier for an Item
+ sku_id : str
+ Unique identifier for a SKU
- - inventory_type: InventoryUpdateRequestInventoryType. infinite or finite
+ inventory_type : InventoryUpdateRequestInventoryType
+ infinite or finite
- - update_quantity: typing.Optional[float]. Adds this quantity to currently store quantity. Can be negative.
+ update_quantity : typing.Optional[float]
+ Adds this quantity to currently store quantity. Can be negative.
- - quantity: typing.Optional[float]. Immediately sets quantity to this value.
+ quantity : typing.Optional[float]
+ Immediately sets quantity to this value.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow import InventoryUpdateRequestInventoryType
- from webflow.client import Webflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ InventoryItem
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.inventory.update(
- collection_id="collection_id",
- item_id="item_id",
- inventory_type=InventoryUpdateRequestInventoryType.INFINITE,
- update_quantity=1.0,
- quantity=100.0,
+ sku_collection_id="6377a7c4b7a79608c34a46f7",
+ sku_id="5e8518516e147040726cc415",
+ inventory_type="infinite",
)
"""
- _request: typing.Dict[str, typing.Any] = {"inventoryType": inventory_type}
- if update_quantity is not OMIT:
- _request["updateQuantity"] = update_quantity
- if quantity is not OMIT:
- _request["quantity"] = quantity
- _response = self._client_wrapper.httpx_client.request(
- "PATCH",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/inventory",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.update(
+ sku_collection_id,
+ sku_id,
+ inventory_type=inventory_type,
+ update_quantity=update_quantity,
+ quantity=quantity,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(InventoryItem, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
class AsyncInventoryClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = AsyncRawInventoryClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawInventoryClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawInventoryClient
+ """
+ return self._raw_client
async def list(
- self, collection_id: str, item_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ self, sku_collection_id: str, sku_id: str, *, request_options: typing.Optional[RequestOptions] = None
) -> InventoryItem:
"""
List the current inventory levels for a particular SKU item.
Required scope | `ecommerce:read`
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ Parameters
+ ----------
+ sku_collection_id : str
+ Unique identifier for a SKU collection. Use the List Collections API to find this ID.
+
+ sku_id : str
+ Unique identifier for a SKU
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - item_id: str. Unique identifier for an Item
+ Returns
+ -------
+ InventoryItem
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.inventory.list(
- collection_id="collection_id",
- item_id="item_id",
- )
+
+
+ async def main() -> None:
+ await client.inventory.list(
+ sku_collection_id="6377a7c4b7a79608c34a46f7",
+ sku_id="5e8518516e147040726cc415",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/inventory",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(InventoryItem, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.list(sku_collection_id, sku_id, request_options=request_options)
+ return _response.data
async def update(
self,
- collection_id: str,
- item_id: str,
+ sku_collection_id: str,
+ sku_id: str,
*,
inventory_type: InventoryUpdateRequestInventoryType,
update_quantity: typing.Optional[float] = OMIT,
@@ -280,87 +207,66 @@ async def update(
request_options: typing.Optional[RequestOptions] = None,
) -> InventoryItem:
"""
- Updates the current inventory levels for a particular SKU item. Updates may be given in one or two methods, absolutely or incrementally. Absolute updates are done by setting `quantity` directly. Incremental updates are by specifying the inventory delta in `updateQuantity` which is then added to the `quantity` stored on the server.
+ Updates the current inventory levels for a particular SKU item.
+
+ Updates may be given in one or two methods, absolutely or incrementally.
+ - Absolute updates are done by setting `quantity` directly.
+ - Incremental updates are by specifying the inventory delta in `updateQuantity` which is then added to the `quantity` stored on the server.
Required scope | `ecommerce:write`
- Parameters:
- - collection_id: str. Unique identifier for a Collection
+ Parameters
+ ----------
+ sku_collection_id : str
+ Unique identifier for a SKU collection. Use the List Collections API to find this ID.
- - item_id: str. Unique identifier for an Item
+ sku_id : str
+ Unique identifier for a SKU
- - inventory_type: InventoryUpdateRequestInventoryType. infinite or finite
+ inventory_type : InventoryUpdateRequestInventoryType
+ infinite or finite
- - update_quantity: typing.Optional[float]. Adds this quantity to currently store quantity. Can be negative.
+ update_quantity : typing.Optional[float]
+ Adds this quantity to currently store quantity. Can be negative.
- - quantity: typing.Optional[float]. Immediately sets quantity to this value.
+ quantity : typing.Optional[float]
+ Immediately sets quantity to this value.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow import InventoryUpdateRequestInventoryType
- from webflow.client import AsyncWebflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ InventoryItem
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.inventory.update(
- collection_id="collection_id",
- item_id="item_id",
- inventory_type=InventoryUpdateRequestInventoryType.INFINITE,
- update_quantity=1.0,
- quantity=100.0,
- )
+
+
+ async def main() -> None:
+ await client.inventory.update(
+ sku_collection_id="6377a7c4b7a79608c34a46f7",
+ sku_id="5e8518516e147040726cc415",
+ inventory_type="infinite",
+ )
+
+
+ asyncio.run(main())
"""
- _request: typing.Dict[str, typing.Any] = {"inventoryType": inventory_type}
- if update_quantity is not OMIT:
- _request["updateQuantity"] = update_quantity
- if quantity is not OMIT:
- _request["quantity"] = quantity
- _response = await self._client_wrapper.httpx_client.request(
- "PATCH",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/inventory",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.update(
+ sku_collection_id,
+ sku_id,
+ inventory_type=inventory_type,
+ update_quantity=update_quantity,
+ quantity=quantity,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(InventoryItem, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
diff --git a/src/webflow/resources/inventory/raw_client.py b/src/webflow/resources/inventory/raw_client.py
new file mode 100644
index 0000000..af0c454
--- /dev/null
+++ b/src/webflow/resources/inventory/raw_client.py
@@ -0,0 +1,598 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from ...core.api_error import ApiError
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.http_response import AsyncHttpResponse, HttpResponse
+from ...core.jsonable_encoder import jsonable_encoder
+from ...core.parse_error import ParsingError
+from ...core.pydantic_utilities import parse_obj_as
+from ...core.request_options import RequestOptions
+from ...errors.bad_request_error import BadRequestError
+from ...errors.conflict_error import ConflictError
+from ...errors.forbidden_error import ForbiddenError
+from ...errors.internal_server_error import InternalServerError
+from ...errors.not_found_error import NotFoundError
+from ...errors.too_many_requests_error import TooManyRequestsError
+from ...errors.unauthorized_error import UnauthorizedError
+from ...types.error import Error
+from ...types.inventory_item import InventoryItem
+from .types.inventory_update_request_inventory_type import InventoryUpdateRequestInventoryType
+from pydantic import ValidationError
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RawInventoryClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def list(
+ self, sku_collection_id: str, sku_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[InventoryItem]:
+ """
+ List the current inventory levels for a particular SKU item.
+
+ Required scope | `ecommerce:read`
+
+ Parameters
+ ----------
+ sku_collection_id : str
+ Unique identifier for a SKU collection. Use the List Collections API to find this ID.
+
+ sku_id : str
+ Unique identifier for a SKU
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[InventoryItem]
+ Request was successful
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"collections/{jsonable_encoder(sku_collection_id)}/items/{jsonable_encoder(sku_id)}/inventory",
+ base_url=self._client_wrapper.get_environment().base,
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ InventoryItem,
+ parse_obj_as(
+ type_=InventoryItem, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def update(
+ self,
+ sku_collection_id: str,
+ sku_id: str,
+ *,
+ inventory_type: InventoryUpdateRequestInventoryType,
+ update_quantity: typing.Optional[float] = OMIT,
+ quantity: typing.Optional[float] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[InventoryItem]:
+ """
+ Updates the current inventory levels for a particular SKU item.
+
+ Updates may be given in one or two methods, absolutely or incrementally.
+ - Absolute updates are done by setting `quantity` directly.
+ - Incremental updates are by specifying the inventory delta in `updateQuantity` which is then added to the `quantity` stored on the server.
+
+ Required scope | `ecommerce:write`
+
+ Parameters
+ ----------
+ sku_collection_id : str
+ Unique identifier for a SKU collection. Use the List Collections API to find this ID.
+
+ sku_id : str
+ Unique identifier for a SKU
+
+ inventory_type : InventoryUpdateRequestInventoryType
+ infinite or finite
+
+ update_quantity : typing.Optional[float]
+ Adds this quantity to currently store quantity. Can be negative.
+
+ quantity : typing.Optional[float]
+ Immediately sets quantity to this value.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[InventoryItem]
+ Request was successful
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"collections/{jsonable_encoder(sku_collection_id)}/items/{jsonable_encoder(sku_id)}/inventory",
+ base_url=self._client_wrapper.get_environment().base,
+ method="PATCH",
+ json={
+ "inventoryType": inventory_type,
+ "updateQuantity": update_quantity,
+ "quantity": quantity,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ InventoryItem,
+ parse_obj_as(
+ type_=InventoryItem, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawInventoryClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def list(
+ self, sku_collection_id: str, sku_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[InventoryItem]:
+ """
+ List the current inventory levels for a particular SKU item.
+
+ Required scope | `ecommerce:read`
+
+ Parameters
+ ----------
+ sku_collection_id : str
+ Unique identifier for a SKU collection. Use the List Collections API to find this ID.
+
+ sku_id : str
+ Unique identifier for a SKU
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[InventoryItem]
+ Request was successful
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"collections/{jsonable_encoder(sku_collection_id)}/items/{jsonable_encoder(sku_id)}/inventory",
+ base_url=self._client_wrapper.get_environment().base,
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ InventoryItem,
+ parse_obj_as(
+ type_=InventoryItem, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def update(
+ self,
+ sku_collection_id: str,
+ sku_id: str,
+ *,
+ inventory_type: InventoryUpdateRequestInventoryType,
+ update_quantity: typing.Optional[float] = OMIT,
+ quantity: typing.Optional[float] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[InventoryItem]:
+ """
+ Updates the current inventory levels for a particular SKU item.
+
+ Updates may be given in one or two methods, absolutely or incrementally.
+ - Absolute updates are done by setting `quantity` directly.
+ - Incremental updates are by specifying the inventory delta in `updateQuantity` which is then added to the `quantity` stored on the server.
+
+ Required scope | `ecommerce:write`
+
+ Parameters
+ ----------
+ sku_collection_id : str
+ Unique identifier for a SKU collection. Use the List Collections API to find this ID.
+
+ sku_id : str
+ Unique identifier for a SKU
+
+ inventory_type : InventoryUpdateRequestInventoryType
+ infinite or finite
+
+ update_quantity : typing.Optional[float]
+ Adds this quantity to currently store quantity. Can be negative.
+
+ quantity : typing.Optional[float]
+ Immediately sets quantity to this value.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[InventoryItem]
+ Request was successful
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"collections/{jsonable_encoder(sku_collection_id)}/items/{jsonable_encoder(sku_id)}/inventory",
+ base_url=self._client_wrapper.get_environment().base,
+ method="PATCH",
+ json={
+ "inventoryType": inventory_type,
+ "updateQuantity": update_quantity,
+ "quantity": quantity,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ InventoryItem,
+ parse_obj_as(
+ type_=InventoryItem, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/inventory/types/__init__.py b/src/webflow/resources/inventory/types/__init__.py
index e929f4e..2cc6148 100644
--- a/src/webflow/resources/inventory/types/__init__.py
+++ b/src/webflow/resources/inventory/types/__init__.py
@@ -1,5 +1,38 @@
# This file was auto-generated by Fern from our API Definition.
-from .inventory_update_request_inventory_type import InventoryUpdateRequestInventoryType
+# isort: skip_file
-__all__ = ["InventoryUpdateRequestInventoryType"]
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .ecomm_inventory_changed_payload import EcommInventoryChangedPayload
+ from .inventory_update_request_inventory_type import InventoryUpdateRequestInventoryType
+_dynamic_imports: typing.Dict[str, str] = {
+ "EcommInventoryChangedPayload": ".ecomm_inventory_changed_payload",
+ "InventoryUpdateRequestInventoryType": ".inventory_update_request_inventory_type",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = ["EcommInventoryChangedPayload", "InventoryUpdateRequestInventoryType"]
diff --git a/src/webflow/resources/inventory/types/ecomm_inventory_changed_payload.py b/src/webflow/resources/inventory/types/ecomm_inventory_changed_payload.py
new file mode 100644
index 0000000..729740d
--- /dev/null
+++ b/src/webflow/resources/inventory/types/ecomm_inventory_changed_payload.py
@@ -0,0 +1,27 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ....core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ....core.serialization import FieldMetadata
+from ....types.inventory_item import InventoryItem
+
+
+class EcommInventoryChangedPayload(UniversalBaseModel):
+ trigger_type: typing_extensions.Annotated[
+ typing.Optional[typing.Literal["ecomm_inventory_changed"]],
+ FieldMetadata(alias="triggerType"),
+ pydantic.Field(alias="triggerType"),
+ ] = None
+ payload: typing.Optional[InventoryItem] = 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/inventory/types/inventory_update_request_inventory_type.py b/src/webflow/resources/inventory/types/inventory_update_request_inventory_type.py
index f4d4643..90479e3 100644
--- a/src/webflow/resources/inventory/types/inventory_update_request_inventory_type.py
+++ b/src/webflow/resources/inventory/types/inventory_update_request_inventory_type.py
@@ -1,21 +1,5 @@
# This file was auto-generated by Fern from our API Definition.
-import enum
import typing
-T_Result = typing.TypeVar("T_Result")
-
-
-class InventoryUpdateRequestInventoryType(str, enum.Enum):
- """
- infinite or finite
- """
-
- INFINITE = "infinite"
- FINITE = "finite"
-
- def visit(self, infinite: typing.Callable[[], T_Result], finite: typing.Callable[[], T_Result]) -> T_Result:
- if self is InventoryUpdateRequestInventoryType.INFINITE:
- return infinite()
- if self is InventoryUpdateRequestInventoryType.FINITE:
- return finite()
+InventoryUpdateRequestInventoryType = typing.Union[typing.Literal["infinite", "finite"], typing.Any]
diff --git a/src/webflow/resources/orders/__init__.py b/src/webflow/resources/orders/__init__.py
index 94cbc01..7af8880 100644
--- a/src/webflow/resources/orders/__init__.py
+++ b/src/webflow/resources/orders/__init__.py
@@ -1,5 +1,34 @@
# This file was auto-generated by Fern from our API Definition.
-from .types import OrdersRefundRequestReason
+# isort: skip_file
-__all__ = ["OrdersRefundRequestReason"]
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .types import OrdersListRequestStatus, OrdersRefundRequestReason
+_dynamic_imports: typing.Dict[str, str] = {"OrdersListRequestStatus": ".types", "OrdersRefundRequestReason": ".types"}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = ["OrdersListRequestStatus", "OrdersRefundRequestReason"]
diff --git a/src/webflow/resources/orders/client.py b/src/webflow/resources/orders/client.py
index 3c079cb..ef55043 100644
--- a/src/webflow/resources/orders/client.py
+++ b/src/webflow/resources/orders/client.py
@@ -1,45 +1,41 @@
# This file was auto-generated by Fern from our API Definition.
import typing
-import urllib.parse
-from json.decoder import JSONDecodeError
-from ...core.api_error import ApiError
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from ...core.jsonable_encoder import jsonable_encoder
-from ...core.remove_none_from_dict import remove_none_from_dict
from ...core.request_options import RequestOptions
-from ...errors.bad_request_error import BadRequestError
-from ...errors.conflict_error import ConflictError
-from ...errors.forbidden_error import ForbiddenError
-from ...errors.internal_server_error import InternalServerError
-from ...errors.not_found_error import NotFoundError
-from ...errors.too_many_requests_error import TooManyRequestsError
-from ...errors.unauthorized_error import UnauthorizedError
from ...types.order import Order
from ...types.order_list import OrderList
+from .raw_client import AsyncRawOrdersClient, RawOrdersClient
+from .types.orders_list_request_status import OrdersListRequestStatus
from .types.orders_refund_request_reason import OrdersRefundRequestReason
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
class OrdersClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = RawOrdersClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawOrdersClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawOrdersClient
+ """
+ return self._raw_client
def list(
self,
site_id: str,
*,
- status: typing.Optional[str] = None,
- offset: typing.Optional[float] = None,
- limit: typing.Optional[float] = None,
+ status: typing.Optional[OrdersListRequestStatus] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> OrderList:
"""
@@ -47,144 +43,84 @@ def list(
Required scope | `ecommerce:read`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- - status: typing.Optional[str]. Filter the orders by status
+ 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
+ offset : typing.Optional[int]
+ 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)
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ OrderList
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.orders.list(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
+ status="pending",
+ offset=1,
+ limit=1,
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/orders"
- ),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "status": status,
- "offset": offset,
- "limit": limit,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.list(
+ site_id, status=status, offset=offset, limit=limit, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(OrderList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
def get(self, site_id: str, order_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Order:
"""
- Retrieve a single product by its id. All of its SKUs will also be retrieved.
+ Retrieve a single product by its ID. All of its SKUs will also be
+ retrieved.
Required scope | `ecommerce:read`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ order_id : str
+ Unique identifier for an Order
- - order_id: str. Unique identifier for an Order
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Returns
+ -------
+ Order
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.orders.get(
- site_id="site_id",
- order_id="order_id",
+ site_id="580e63e98c9a982ac9b8b741",
+ order_id="5e8518516e147040726cc415",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Order, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.get(site_id, order_id, request_options=request_options)
+ return _response.data
def update(
self,
@@ -198,96 +134,62 @@ def update(
request_options: typing.Optional[RequestOptions] = None,
) -> Order:
"""
- 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.
+ 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`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- - order_id: str. Unique identifier for an Order
+ order_id : str
+ Unique identifier for an Order
- - comment: typing.Optional[str]. Arbitrary data for your records
+ comment : typing.Optional[str]
+ Arbitrary data for your records
- - shipping_provider: typing.Optional[str]. Company or method used to ship order
+ shipping_provider : typing.Optional[str]
+ Company or method used to ship order
- - shipping_tracking: typing.Optional[str]. Tracking number for order shipment
+ shipping_tracking : typing.Optional[str]
+ Tracking number for order shipment
- - shipping_tracking_url: typing.Optional[str]. URL to track order shipment
+ shipping_tracking_url : typing.Optional[str]
+ URL to track order shipment
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Order
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.orders.update(
- site_id="site_id",
- order_id="order_id",
- comment="Example comment to myself",
- shipping_provider="Shipping Company, Co.",
- shipping_tracking="tr00000000001",
- shipping_tracking_url="https://www.shippingcompany.com/tracking/tr00000000001",
+ site_id="580e63e98c9a982ac9b8b741",
+ order_id="5e8518516e147040726cc415",
)
"""
- _request: typing.Dict[str, typing.Any] = {}
- if comment is not OMIT:
- _request["comment"] = comment
- if shipping_provider is not OMIT:
- _request["shippingProvider"] = shipping_provider
- if shipping_tracking is not OMIT:
- _request["shippingTracking"] = shipping_tracking
- if shipping_tracking_url is not OMIT:
- _request["shippingTrackingURL"] = shipping_tracking_url
- _response = self._client_wrapper.httpx_client.request(
- "PATCH",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.update(
+ site_id,
+ order_id,
+ comment=comment,
+ shipping_provider=shipping_provider,
+ shipping_tracking=shipping_tracking,
+ shipping_tracking_url=shipping_tracking_url,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Order, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
def update_fulfill(
self,
@@ -302,76 +204,41 @@ def update_fulfill(
Required scope | `ecommerce:write`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ order_id : str
+ Unique identifier for an Order
- - order_id: str. Unique identifier for an Order
+ send_order_fulfilled_email : typing.Optional[bool]
+ Whether or not the Order Fulfilled email should be sent
- - send_order_fulfilled_email: typing.Optional[bool]. Whether or not the Order Fulfilled email should be sent
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Returns
+ -------
+ Order
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.orders.update_fulfill(
- site_id="site_id",
- order_id="order_id",
+ site_id="580e63e98c9a982ac9b8b741",
+ order_id="5e8518516e147040726cc415",
)
"""
- _request: typing.Dict[str, typing.Any] = {}
- if send_order_fulfilled_email is not OMIT:
- _request["sendOrderFulfilledEmail"] = send_order_fulfilled_email
- _response = self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}/fulfill",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.update_fulfill(
+ site_id, order_id, send_order_fulfilled_email=send_order_fulfilled_email, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Order, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
def update_unfulfill(
self, site_id: str, order_id: str, *, request_options: typing.Optional[RequestOptions] = None
@@ -381,68 +248,36 @@ def update_unfulfill(
Required scope | `ecommerce:write`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ order_id : str
+ Unique identifier for an Order
- - order_id: str. Unique identifier for an Order
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Returns
+ -------
+ Order
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.orders.update_unfulfill(
- site_id="site_id",
- order_id="order_id",
+ site_id="580e63e98c9a982ac9b8b741",
+ order_id="5e8518516e147040726cc415",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}/unfulfill",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))
- if request_options is not None
- else None,
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Order, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.update_unfulfill(site_id, order_id, request_options=request_options)
+ return _response.data
def refund(
self,
@@ -458,89 +293,63 @@ def refund(
Required scope | `ecommerce:write`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ order_id : str
+ Unique identifier for an Order
+
+ reason : typing.Optional[OrdersRefundRequestReason]
+ The reason for the refund
- - order_id: str. Unique identifier for an Order
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - reason: typing.Optional[OrdersRefundRequestReason]. The reason for the refund
+ Returns
+ -------
+ Order
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.orders.refund(
- site_id="site_id",
- order_id="order_id",
+ site_id="580e63e98c9a982ac9b8b741",
+ order_id="5e8518516e147040726cc415",
)
"""
- _request: typing.Dict[str, typing.Any] = {}
- if reason is not OMIT:
- _request["reason"] = reason.value if reason is not None else None
- _response = self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}/refund",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Order, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.refund(site_id, order_id, reason=reason, request_options=request_options)
+ return _response.data
class AsyncOrdersClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = AsyncRawOrdersClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawOrdersClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawOrdersClient
+ """
+ return self._raw_client
async def list(
self,
site_id: str,
*,
- status: typing.Optional[str] = None,
- offset: typing.Optional[float] = None,
- limit: typing.Optional[float] = None,
+ status: typing.Optional[OrdersListRequestStatus] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> OrderList:
"""
@@ -548,146 +357,102 @@ async def list(
Required scope | `ecommerce:read`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- - status: typing.Optional[str]. Filter the orders by status
+ 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
+ offset : typing.Optional[int]
+ 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)
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ OrderList
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.orders.list(
- site_id="site_id",
- )
+
+
+ async def main() -> None:
+ await client.orders.list(
+ site_id="580e63e98c9a982ac9b8b741",
+ status="pending",
+ offset=1,
+ limit=1,
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/orders"
- ),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "status": status,
- "offset": offset,
- "limit": limit,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.list(
+ site_id, status=status, offset=offset, limit=limit, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(OrderList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
async def get(
self, site_id: str, order_id: str, *, request_options: typing.Optional[RequestOptions] = None
) -> Order:
"""
- Retrieve a single product by its id. All of its SKUs will also be retrieved.
+ Retrieve a single product by its ID. All of its SKUs will also be
+ retrieved.
Required scope | `ecommerce:read`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ 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.
- - order_id: str. Unique identifier for an Order
+ Returns
+ -------
+ Order
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.orders.get(
- site_id="site_id",
- order_id="order_id",
- )
+
+
+ async def main() -> None:
+ await client.orders.get(
+ site_id="580e63e98c9a982ac9b8b741",
+ order_id="5e8518516e147040726cc415",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Order, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.get(site_id, order_id, request_options=request_options)
+ return _response.data
async def update(
self,
@@ -701,96 +466,70 @@ async def update(
request_options: typing.Optional[RequestOptions] = None,
) -> Order:
"""
- 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.
+ 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`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ order_id : str
+ Unique identifier for an Order
+
+ comment : typing.Optional[str]
+ Arbitrary data for your records
- - order_id: str. Unique identifier for an Order
+ shipping_provider : typing.Optional[str]
+ Company or method used to ship order
- - comment: typing.Optional[str]. Arbitrary data for your records
+ shipping_tracking : typing.Optional[str]
+ Tracking number for order shipment
- - shipping_provider: typing.Optional[str]. Company or method used to ship order
+ shipping_tracking_url : typing.Optional[str]
+ URL to track order shipment
- - shipping_tracking: typing.Optional[str]. Tracking number for order shipment
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - shipping_tracking_url: typing.Optional[str]. URL to track order shipment
+ Returns
+ -------
+ Order
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.orders.update(
- site_id="site_id",
- order_id="order_id",
- comment="Example comment to myself",
- shipping_provider="Shipping Company, Co.",
- shipping_tracking="tr00000000001",
- shipping_tracking_url="https://www.shippingcompany.com/tracking/tr00000000001",
- )
+
+
+ async def main() -> None:
+ await client.orders.update(
+ site_id="580e63e98c9a982ac9b8b741",
+ order_id="5e8518516e147040726cc415",
+ )
+
+
+ asyncio.run(main())
"""
- _request: typing.Dict[str, typing.Any] = {}
- if comment is not OMIT:
- _request["comment"] = comment
- if shipping_provider is not OMIT:
- _request["shippingProvider"] = shipping_provider
- if shipping_tracking is not OMIT:
- _request["shippingTracking"] = shipping_tracking
- if shipping_tracking_url is not OMIT:
- _request["shippingTrackingURL"] = shipping_tracking_url
- _response = await self._client_wrapper.httpx_client.request(
- "PATCH",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.update(
+ site_id,
+ order_id,
+ comment=comment,
+ shipping_provider=shipping_provider,
+ shipping_tracking=shipping_tracking,
+ shipping_tracking_url=shipping_tracking_url,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Order, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
async def update_fulfill(
self,
@@ -805,76 +544,49 @@ async def update_fulfill(
Required scope | `ecommerce:write`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ order_id : str
+ Unique identifier for an Order
+
+ send_order_fulfilled_email : typing.Optional[bool]
+ Whether or not the Order Fulfilled email should be sent
- - order_id: str. Unique identifier for an Order
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - send_order_fulfilled_email: typing.Optional[bool]. Whether or not the Order Fulfilled email should be sent
+ Returns
+ -------
+ Order
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.orders.update_fulfill(
- site_id="site_id",
- order_id="order_id",
- )
+
+
+ async def main() -> None:
+ await client.orders.update_fulfill(
+ site_id="580e63e98c9a982ac9b8b741",
+ order_id="5e8518516e147040726cc415",
+ )
+
+
+ asyncio.run(main())
"""
- _request: typing.Dict[str, typing.Any] = {}
- if send_order_fulfilled_email is not OMIT:
- _request["sendOrderFulfilledEmail"] = send_order_fulfilled_email
- _response = await self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}/fulfill",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.update_fulfill(
+ site_id, order_id, send_order_fulfilled_email=send_order_fulfilled_email, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Order, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
async def update_unfulfill(
self, site_id: str, order_id: str, *, request_options: typing.Optional[RequestOptions] = None
@@ -884,68 +596,44 @@ async def update_unfulfill(
Required scope | `ecommerce:write`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- - order_id: str. Unique identifier for an Order
+ order_id : str
+ Unique identifier for an Order
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Order
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.orders.update_unfulfill(
- site_id="site_id",
- order_id="order_id",
- )
+
+
+ async def main() -> None:
+ await client.orders.update_unfulfill(
+ site_id="580e63e98c9a982ac9b8b741",
+ order_id="5e8518516e147040726cc415",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}/unfulfill",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))
- if request_options is not None
- else None,
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Order, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.update_unfulfill(site_id, order_id, request_options=request_options)
+ return _response.data
async def refund(
self,
@@ -961,73 +649,44 @@ async def refund(
Required scope | `ecommerce:write`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- - order_id: str. Unique identifier for an Order
+ order_id : str
+ Unique identifier for an Order
- - reason: typing.Optional[OrdersRefundRequestReason]. The reason for the refund
+ reason : typing.Optional[OrdersRefundRequestReason]
+ The reason for the refund
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Order
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.orders.refund(
- site_id="site_id",
- order_id="order_id",
- )
+
+
+ async def main() -> None:
+ await client.orders.refund(
+ site_id="580e63e98c9a982ac9b8b741",
+ order_id="5e8518516e147040726cc415",
+ )
+
+
+ asyncio.run(main())
"""
- _request: typing.Dict[str, typing.Any] = {}
- if reason is not OMIT:
- _request["reason"] = reason.value if reason is not None else None
- _response = await self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}/refund",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Order, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.refund(site_id, order_id, reason=reason, request_options=request_options)
+ return _response.data
diff --git a/src/webflow/resources/orders/raw_client.py b/src/webflow/resources/orders/raw_client.py
new file mode 100644
index 0000000..be3cd04
--- /dev/null
+++ b/src/webflow/resources/orders/raw_client.py
@@ -0,0 +1,1712 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from ...core.api_error import ApiError
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.http_response import AsyncHttpResponse, HttpResponse
+from ...core.jsonable_encoder import jsonable_encoder
+from ...core.parse_error import ParsingError
+from ...core.pydantic_utilities import parse_obj_as
+from ...core.request_options import RequestOptions
+from ...errors.bad_request_error import BadRequestError
+from ...errors.conflict_error import ConflictError
+from ...errors.forbidden_error import ForbiddenError
+from ...errors.internal_server_error import InternalServerError
+from ...errors.not_found_error import NotFoundError
+from ...errors.too_many_requests_error import TooManyRequestsError
+from ...errors.unauthorized_error import UnauthorizedError
+from ...types.error import Error
+from ...types.order import Order
+from ...types.order_list import OrderList
+from .types.orders_list_request_status import OrdersListRequestStatus
+from .types.orders_refund_request_reason import OrdersRefundRequestReason
+from pydantic import ValidationError
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RawOrdersClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def list(
+ self,
+ site_id: str,
+ *,
+ status: typing.Optional[OrdersListRequestStatus] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[OrderList]:
+ """
+ List all orders created for a given site.
+
+ Required scope | `ecommerce:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ status : typing.Optional[OrdersListRequestStatus]
+ Filter the orders by status
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[OrderList]
+ Request was successful
+ """
+ _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,
+ "offset": offset,
+ "limit": limit,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ OrderList,
+ parse_obj_as(
+ type_=OrderList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def get(
+ self, site_id: str, order_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[Order]:
+ """
+ Retrieve a single product by its ID. All of its SKUs will also be
+ retrieved.
+
+ Required scope | `ecommerce:read`
+
+ 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.
+
+ Returns
+ -------
+ HttpResponse[Order]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Order,
+ parse_obj_as(
+ type_=Order, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def update(
+ self,
+ site_id: str,
+ order_id: str,
+ *,
+ comment: typing.Optional[str] = OMIT,
+ shipping_provider: typing.Optional[str] = OMIT,
+ shipping_tracking: typing.Optional[str] = OMIT,
+ shipping_tracking_url: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[Order]:
+ """
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ order_id : str
+ Unique identifier for an Order
+
+ comment : typing.Optional[str]
+ Arbitrary data for your records
+
+ shipping_provider : typing.Optional[str]
+ Company or method used to ship order
+
+ shipping_tracking : typing.Optional[str]
+ Tracking number for order shipment
+
+ shipping_tracking_url : typing.Optional[str]
+ URL to track order shipment
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Order]
+ Request was successful
+ """
+ _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,
+ "shippingProvider": shipping_provider,
+ "shippingTracking": shipping_tracking,
+ "shippingTrackingURL": shipping_tracking_url,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Order,
+ parse_obj_as(
+ type_=Order, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def update_fulfill(
+ self,
+ site_id: str,
+ order_id: str,
+ *,
+ send_order_fulfilled_email: typing.Optional[bool] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[Order]:
+ """
+ Updates an order's status to fulfilled
+
+ Required scope | `ecommerce:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ order_id : str
+ Unique identifier for an Order
+
+ send_order_fulfilled_email : typing.Optional[bool]
+ Whether or not the Order Fulfilled email should be sent
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Order]
+ Request was successful
+ """
+ _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,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Order,
+ parse_obj_as(
+ type_=Order, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def update_unfulfill(
+ self, site_id: str, order_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[Order]:
+ """
+ Updates an order's status to unfulfilled
+
+ Required scope | `ecommerce:write`
+
+ 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.
+
+ Returns
+ -------
+ HttpResponse[Order]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Order,
+ parse_obj_as(
+ type_=Order, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def refund(
+ self,
+ site_id: str,
+ order_id: str,
+ *,
+ reason: typing.Optional[OrdersRefundRequestReason] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[Order]:
+ """
+ This API will reverse a Stripe charge and refund an order back to a
+ customer. It will also set the order's status to `refunded`.
+
+ Required scope | `ecommerce:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ order_id : str
+ Unique identifier for an Order
+
+ reason : typing.Optional[OrdersRefundRequestReason]
+ The reason for the refund
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Order]
+ Request was successful
+ """
+ _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,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Order,
+ parse_obj_as(
+ type_=Order, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawOrdersClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def list(
+ self,
+ site_id: str,
+ *,
+ status: typing.Optional[OrdersListRequestStatus] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[OrderList]:
+ """
+ List all orders created for a given site.
+
+ Required scope | `ecommerce:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ status : typing.Optional[OrdersListRequestStatus]
+ Filter the orders by status
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[OrderList]
+ Request was successful
+ """
+ _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,
+ "offset": offset,
+ "limit": limit,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ OrderList,
+ parse_obj_as(
+ type_=OrderList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def get(
+ self, site_id: str, order_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[Order]:
+ """
+ Retrieve a single product by its ID. All of its SKUs will also be
+ retrieved.
+
+ Required scope | `ecommerce:read`
+
+ 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.
+
+ Returns
+ -------
+ AsyncHttpResponse[Order]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Order,
+ parse_obj_as(
+ type_=Order, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def update(
+ self,
+ site_id: str,
+ order_id: str,
+ *,
+ comment: typing.Optional[str] = OMIT,
+ shipping_provider: typing.Optional[str] = OMIT,
+ shipping_tracking: typing.Optional[str] = OMIT,
+ shipping_tracking_url: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[Order]:
+ """
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ order_id : str
+ Unique identifier for an Order
+
+ comment : typing.Optional[str]
+ Arbitrary data for your records
+
+ shipping_provider : typing.Optional[str]
+ Company or method used to ship order
+
+ shipping_tracking : typing.Optional[str]
+ Tracking number for order shipment
+
+ shipping_tracking_url : typing.Optional[str]
+ URL to track order shipment
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Order]
+ Request was successful
+ """
+ _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,
+ "shippingProvider": shipping_provider,
+ "shippingTracking": shipping_tracking,
+ "shippingTrackingURL": shipping_tracking_url,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Order,
+ parse_obj_as(
+ type_=Order, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def update_fulfill(
+ self,
+ site_id: str,
+ order_id: str,
+ *,
+ send_order_fulfilled_email: typing.Optional[bool] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[Order]:
+ """
+ Updates an order's status to fulfilled
+
+ Required scope | `ecommerce:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ order_id : str
+ Unique identifier for an Order
+
+ send_order_fulfilled_email : typing.Optional[bool]
+ Whether or not the Order Fulfilled email should be sent
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Order]
+ Request was successful
+ """
+ _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,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Order,
+ parse_obj_as(
+ type_=Order, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def update_unfulfill(
+ self, site_id: str, order_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[Order]:
+ """
+ Updates an order's status to unfulfilled
+
+ Required scope | `ecommerce:write`
+
+ 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.
+
+ Returns
+ -------
+ AsyncHttpResponse[Order]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Order,
+ parse_obj_as(
+ type_=Order, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def refund(
+ self,
+ site_id: str,
+ order_id: str,
+ *,
+ reason: typing.Optional[OrdersRefundRequestReason] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[Order]:
+ """
+ This API will reverse a Stripe charge and refund an order back to a
+ customer. It will also set the order's status to `refunded`.
+
+ Required scope | `ecommerce:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ order_id : str
+ Unique identifier for an Order
+
+ reason : typing.Optional[OrdersRefundRequestReason]
+ The reason for the refund
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Order]
+ Request was successful
+ """
+ _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,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Order,
+ parse_obj_as(
+ type_=Order, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/orders/types/__init__.py b/src/webflow/resources/orders/types/__init__.py
index a219c24..d06e415 100644
--- a/src/webflow/resources/orders/types/__init__.py
+++ b/src/webflow/resources/orders/types/__init__.py
@@ -1,5 +1,38 @@
# This file was auto-generated by Fern from our API Definition.
-from .orders_refund_request_reason import OrdersRefundRequestReason
+# isort: skip_file
-__all__ = ["OrdersRefundRequestReason"]
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .orders_list_request_status import OrdersListRequestStatus
+ from .orders_refund_request_reason import OrdersRefundRequestReason
+_dynamic_imports: typing.Dict[str, str] = {
+ "OrdersListRequestStatus": ".orders_list_request_status",
+ "OrdersRefundRequestReason": ".orders_refund_request_reason",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = ["OrdersListRequestStatus", "OrdersRefundRequestReason"]
diff --git a/src/webflow/resources/orders/types/orders_list_request_status.py b/src/webflow/resources/orders/types/orders_list_request_status.py
new file mode 100644
index 0000000..dfa1af7
--- /dev/null
+++ b/src/webflow/resources/orders/types/orders_list_request_status.py
@@ -0,0 +1,7 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+OrdersListRequestStatus = typing.Union[
+ typing.Literal["pending", "refunded", "dispute-lost", "fulfilled", "disputed", "unfulfilled"], typing.Any
+]
diff --git a/src/webflow/resources/orders/types/orders_refund_request_reason.py b/src/webflow/resources/orders/types/orders_refund_request_reason.py
index a3025a6..149ae86 100644
--- a/src/webflow/resources/orders/types/orders_refund_request_reason.py
+++ b/src/webflow/resources/orders/types/orders_refund_request_reason.py
@@ -1,29 +1,5 @@
# This file was auto-generated by Fern from our API Definition.
-import enum
import typing
-T_Result = typing.TypeVar("T_Result")
-
-
-class OrdersRefundRequestReason(str, enum.Enum):
- """
- The reason for the refund
- """
-
- DUPLICATE = "duplicate"
- FRAUDULENT = "fraudulent"
- REQUESTED = "requested"
-
- def visit(
- self,
- duplicate: typing.Callable[[], T_Result],
- fraudulent: typing.Callable[[], T_Result],
- requested: typing.Callable[[], T_Result],
- ) -> T_Result:
- if self is OrdersRefundRequestReason.DUPLICATE:
- return duplicate()
- if self is OrdersRefundRequestReason.FRAUDULENT:
- return fraudulent()
- if self is OrdersRefundRequestReason.REQUESTED:
- return requested()
+OrdersRefundRequestReason = typing.Union[typing.Literal["duplicate", "fraudulent", "requested"], typing.Any]
diff --git a/src/webflow/resources/pages/__init__.py b/src/webflow/resources/pages/__init__.py
index 58f0629..25684a4 100644
--- a/src/webflow/resources/pages/__init__.py
+++ b/src/webflow/resources/pages/__init__.py
@@ -1,6 +1,52 @@
# This file was auto-generated by Fern from our API Definition.
-from .types import DomWriteNodesItem
-from .resources import scripts
+# isort: skip_file
-__all__ = ["DomWriteNodesItem", "scripts"]
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .types import (
+ PageDomWriteNodesItem,
+ PageMetadataWriteOpenGraph,
+ PageMetadataWriteSeo,
+ UpdateStaticContentResponse,
+ )
+ from .resources import scripts
+_dynamic_imports: typing.Dict[str, str] = {
+ "PageDomWriteNodesItem": ".types",
+ "PageMetadataWriteOpenGraph": ".types",
+ "PageMetadataWriteSeo": ".types",
+ "UpdateStaticContentResponse": ".types",
+ "scripts": ".resources",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = [
+ "PageDomWriteNodesItem",
+ "PageMetadataWriteOpenGraph",
+ "PageMetadataWriteSeo",
+ "UpdateStaticContentResponse",
+ "scripts",
+]
diff --git a/src/webflow/resources/pages/client.py b/src/webflow/resources/pages/client.py
index 8b3b1f6..9f6f980 100644
--- a/src/webflow/resources/pages/client.py
+++ b/src/webflow/resources/pages/client.py
@@ -1,890 +1,835 @@
# This file was auto-generated by Fern from our API Definition.
+from __future__ import annotations
+
import typing
-import urllib.parse
-from json.decoder import JSONDecodeError
-from ...core.api_error import ApiError
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from ...core.jsonable_encoder import jsonable_encoder
-from ...core.remove_none_from_dict import remove_none_from_dict
from ...core.request_options import RequestOptions
-from ...errors.bad_request_error import BadRequestError
-from ...errors.forbidden_error import ForbiddenError
-from ...errors.internal_server_error import InternalServerError
-from ...errors.not_found_error import NotFoundError
-from ...errors.too_many_requests_error import TooManyRequestsError
-from ...errors.unauthorized_error import UnauthorizedError
from ...types.dom import Dom
from ...types.page import Page
from ...types.page_list import PageList
-from .resources.scripts.client import AsyncScriptsClient, ScriptsClient
-from .types.dom_write_nodes_item import DomWriteNodesItem
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
+from .raw_client import AsyncRawPagesClient, RawPagesClient
+from .types.page_dom_write_nodes_item import PageDomWriteNodesItem
+from .types.page_metadata_write_open_graph import PageMetadataWriteOpenGraph
+from .types.page_metadata_write_seo import PageMetadataWriteSeo
+from .types.update_static_content_response import UpdateStaticContentResponse
+
+if typing.TYPE_CHECKING:
+ from .resources.scripts.client import AsyncScriptsClient, ScriptsClient
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
class PagesClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._raw_client = RawPagesClient(client_wrapper=client_wrapper)
self._client_wrapper = client_wrapper
- self.scripts = ScriptsClient(client_wrapper=self._client_wrapper)
+ self._scripts: typing.Optional[ScriptsClient] = None
+
+ @property
+ def with_raw_response(self) -> RawPagesClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawPagesClient
+ """
+ return self._raw_client
def list(
self,
site_id: str,
*,
- locale: typing.Optional[str] = None,
- limit: typing.Optional[float] = None,
- offset: typing.Optional[float] = None,
+ locale_id: typing.Optional[str] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> PageList:
"""
- List of all pages for a site Required scope | `pages:read`
+ List of all pages for a site.
+
+ Required scope | `pages:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
- Parameters:
- - site_id: str. Unique identifier for a Site
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
- - locale: typing.Optional[str]. Unique identifier for a specific locale. Applicable, when using localization.
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
- - limit: typing.Optional[float]. Maximum number of records to be returned (max limit: 100)
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
- - offset: typing.Optional[float]. Offset used for pagination if the results have more than limit records
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Returns
+ -------
+ PageList
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.pages.list(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
+ locale_id="65427cf400e02b306eaa04a0",
+ limit=1,
+ offset=1,
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/pages"),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "locale": locale,
- "limit": limit,
- "offset": offset,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.list(
+ site_id, locale_id=locale_id, limit=limit, offset=offset, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(PageList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
def get_metadata(
self,
page_id: str,
*,
- locale: typing.Optional[str] = None,
+ locale_id: typing.Optional[str] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> Page:
"""
- Get metadata information for a single page Required scope | `pages:read`
+ Get metadata information for a single page.
+
+ Required scope | `pages:read`
- Parameters:
- - page_id: str. Unique identifier for a Page
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
- - locale: typing.Optional[str]. Unique identifier for a specific locale. Applicable, when using localization.
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Page
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.pages.get_metadata(
- page_id="page_id",
+ page_id="63c720f9347c2139b248e552",
+ locale_id="65427cf400e02b306eaa04a0",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"pages/{jsonable_encoder(page_id)}"),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "locale": locale,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Page, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.get_metadata(page_id, locale_id=locale_id, request_options=request_options)
+ return _response.data
def update_page_settings(
self,
page_id: str,
*,
- locale: typing.Optional[str] = None,
- request: Page,
+ locale_id: typing.Optional[str] = None,
+ title: typing.Optional[str] = OMIT,
+ slug: typing.Optional[str] = OMIT,
+ seo: typing.Optional[PageMetadataWriteSeo] = OMIT,
+ open_graph: typing.Optional[PageMetadataWriteOpenGraph] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
) -> Page:
"""
- Update Page-level metadata, including SEO and Open Graph fields. Required scope | `pages:write`
+ Update Page-level metadata, including SEO and Open Graph fields.
+
+ Required scope | `pages:write`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
- Parameters:
- - page_id: str. Unique identifier for a Page
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
- - locale: typing.Optional[str]. Unique identifier for a specific locale. Applicable, when using localization.
+ title : typing.Optional[str]
+ Title for the page
- - request: Page.
+ slug : typing.Optional[str]
+ Slug for the page.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- import datetime
- from webflow import Page, PageOpenGraph, PageSeo
- from webflow.client import Webflow
+ **Note:** Updating slugs in secondary locales is only supported in Advanced and Enterprise localization add-on plans.
+
+ seo : typing.Optional[PageMetadataWriteSeo]
+ SEO-related fields for the Page
+
+ open_graph : typing.Optional[PageMetadataWriteOpenGraph]
+ Open Graph fields for the Page
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Page
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
+ from webflow.resources.pages import (
+ PageMetadataWriteOpenGraph,
+ PageMetadataWriteSeo,
+ )
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.pages.update_page_settings(
- page_id="page_id",
- request=Page(
- id="6390c49774a71f0e3c1a08ee",
- site_id="6390c49674a71f84b51a08d8",
- title="Blog Categories Template",
- slug="detail_blog-category",
- parent_id="6419db964a9c435aa3af6251",
- collection_id="6390c49774a71f12831a08e3",
- created_on=datetime.datetime.fromisoformat(
- "2018-10-14 21:55:49+00:00",
- ),
- last_updated=datetime.datetime.fromisoformat(
- "2022-12-07 16:51:37+00:00",
- ),
- archived=False,
- draft=False,
- can_branch=True,
- is_members_only=False,
- seo=PageSeo(
- title="CoffeeStyle eCommerce - Webflow HTML website template",
- description="This Webflow template offers a quick start into an e-commerce / memberships site",
- ),
- open_graph=PageOpenGraph(
- title="CoffeeStyle eCommerce - Webflow HTML website template",
- title_copied=True,
- description="This Webflow template offers a quick start into an e-commerce / memberships site",
- description_copied=True,
- ),
+ page_id="63c720f9347c2139b248e552",
+ locale_id="65427cf400e02b306eaa04a0",
+ title="Guide to the Galaxy",
+ slug="guide-to-the-galaxy",
+ seo=PageMetadataWriteSeo(
+ 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.",
+ ),
+ open_graph=PageMetadataWriteOpenGraph(
+ title="Explore the Cosmos with The Ultimate Guide",
+ title_copied=False,
+ description="Dive deep into the mysteries of the universe with your guide to everything galactic.",
+ description_copied=False,
),
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "PUT",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"pages/{jsonable_encoder(page_id)}"),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "locale": locale,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- json=jsonable_encoder(request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.update_page_settings(
+ page_id,
+ locale_id=locale_id,
+ title=title,
+ slug=slug,
+ seo=seo,
+ open_graph=open_graph,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Page, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
def get_content(
self,
page_id: str,
*,
- locale: typing.Optional[str] = None,
+ locale_id: typing.Optional[str] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> Dom:
"""
- Get static content from a static page. 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 Required scope | `pages:read`
+ Get text and component instance content from a static page.
- Parameters:
- - page_id: str. Unique identifier for a Page
+ Localization
- - locale: typing.Optional[str]. Unique identifier for a specific locale. Applicable, when using localization.
+ Required scope | `pages:read`
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Dom
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.pages.get_content(
- page_id="page_id",
+ page_id="63c720f9347c2139b248e552",
+ locale_id="65427cf400e02b306eaa04a0",
+ limit=1,
+ offset=1,
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"pages/{jsonable_encoder(page_id)}/dom"),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "locale": locale,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.get_content(
+ page_id, locale_id=locale_id, limit=limit, offset=offset, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Dom, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
def update_static_content(
self,
page_id: str,
*,
- locale: str,
- nodes: typing.Sequence[DomWriteNodesItem],
+ locale_id: str,
+ nodes: typing.Sequence[PageDomWriteNodesItem],
request_options: typing.Optional[RequestOptions] = None,
- ) -> Dom:
+ ) -> UpdateStaticContentResponse:
"""
- Update static content on a static page. This endpoint supports sending 1000 nodes per request. Required scope | `pages:write`
-
- Parameters:
- - page_id: str. Unique identifier for a Page
-
- - locale: str. The locale identifier.
-
- - nodes: typing.Sequence[DomWriteNodesItem].
-
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow import DomWriteNodesItem
- from webflow.client import Webflow
+ This endpoint updates content on a static page in **secondary locales**. It supports updating up to 1000 nodes in a single request.
+
+ Before making updates:
+ 1. Use the [get page content](/data/reference/pages-and-components/pages/get-content) endpoint to identify available content nodes and their types.
+ 2. If the page has component instances, retrieve the component's properties that you'll override using the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint.
+ 3. DOM elements may include a `data-w-id` attribute. This attribute is used by Webflow to maintain custom attributes and links across locales. Always include the original `data-w-id` value in your update requests to ensure consistent behavior across all locales.
+
+
+ This endpoint is specifically for localized pages. Ensure that the specified `localeId` is a valid **secondary locale** for the site otherwise the request will fail.
+
+
+ Required scope | `pages:write`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ locale_id : str
+ The locale identifier.
+
+ nodes : typing.Sequence[PageDomWriteNodesItem]
+ List of DOM Nodes with the new content that will be updated in each node.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ UpdateStaticContentResponse
+ Request was successful
+
+ Examples
+ --------
+ from webflow import (
+ ComponentInstanceNodePropertyOverridesWrite,
+ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem,
+ Select,
+ SelectNodeWriteChoicesItem,
+ SubmitButtonNodeWrite,
+ TextInputNodeWrite,
+ TextNodeWrite,
+ Webflow,
+ )
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.pages.update_static_content(
- page_id="page_id",
- locale="locale",
+ page_id="63c720f9347c2139b248e552",
+ locale_id="localeId",
nodes=[
- DomWriteNodesItem(
- node_id="guide-title-id",
- text="Hello world ",
- )
+ TextNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad623",
+ text="The Hitchhiker's Guide to the Galaxy ",
+ ),
+ TextNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad627",
+ text="Don't Panic! Always know where your towel is.
",
+ ),
+ Select(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad635",
+ choices=[
+ SelectNodeWriteChoicesItem(
+ value="choice-1",
+ text="First choice",
+ ),
+ SelectNodeWriteChoicesItem(
+ value="choice-2",
+ text="Second choice",
+ ),
+ ],
+ ),
+ TextInputNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad642",
+ placeholder="Enter something here...",
+ ),
+ SubmitButtonNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad671",
+ value="Submit",
+ waiting_text="Submitting...",
+ ),
+ ComponentInstanceNodePropertyOverridesWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad629",
+ property_overrides=[
+ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem(
+ property_id="7dd14c08-2e96-8d3d-2b19-b5c03642a0f0",
+ text="
Time is an illusion ",
+ ),
+ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem(
+ property_id="7dd14c08-2e96-8d3d-2b19-b5c03642a0f1",
+ text="Life, the Universe and Everything",
+ ),
+ ],
+ ),
],
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"pages/{jsonable_encoder(page_id)}/dom"),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "locale": locale,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- json=jsonable_encoder({"nodes": nodes})
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder({"nodes": nodes}),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.update_static_content(
+ page_id, locale_id=locale_id, nodes=nodes, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Dom, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
+
+ @property
+ def scripts(self):
+ if self._scripts is None:
+ from .resources.scripts.client import ScriptsClient # noqa: E402
+
+ self._scripts = ScriptsClient(client_wrapper=self._client_wrapper)
+ return self._scripts
class AsyncPagesClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._raw_client = AsyncRawPagesClient(client_wrapper=client_wrapper)
self._client_wrapper = client_wrapper
- self.scripts = AsyncScriptsClient(client_wrapper=self._client_wrapper)
+ self._scripts: typing.Optional[AsyncScriptsClient] = None
+
+ @property
+ def with_raw_response(self) -> AsyncRawPagesClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawPagesClient
+ """
+ return self._raw_client
async def list(
self,
site_id: str,
*,
- locale: typing.Optional[str] = None,
- limit: typing.Optional[float] = None,
- offset: typing.Optional[float] = None,
+ locale_id: typing.Optional[str] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> PageList:
"""
- List of all pages for a site Required scope | `pages:read`
+ List of all pages for a site.
+
+ Required scope | `pages:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
- Parameters:
- - site_id: str. Unique identifier for a Site
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
- - locale: typing.Optional[str]. Unique identifier for a specific locale. Applicable, when using localization.
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
- - limit: typing.Optional[float]. Maximum number of records to be returned (max limit: 100)
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
- - offset: typing.Optional[float]. Offset used for pagination if the results have more than limit records
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Returns
+ -------
+ PageList
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.pages.list(
- site_id="site_id",
- )
+
+
+ async def main() -> None:
+ await client.pages.list(
+ site_id="580e63e98c9a982ac9b8b741",
+ locale_id="65427cf400e02b306eaa04a0",
+ limit=1,
+ offset=1,
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/pages"),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "locale": locale,
- "limit": limit,
- "offset": offset,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.list(
+ site_id, locale_id=locale_id, limit=limit, offset=offset, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(PageList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
async def get_metadata(
self,
page_id: str,
*,
- locale: typing.Optional[str] = None,
+ locale_id: typing.Optional[str] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> Page:
"""
- Get metadata information for a single page Required scope | `pages:read`
+ Get metadata information for a single page.
- Parameters:
- - page_id: str. Unique identifier for a Page
+ Required scope | `pages:read`
- - locale: typing.Optional[str]. Unique identifier for a specific locale. Applicable, when using localization.
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Page
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.pages.get_metadata(
- page_id="page_id",
- )
+
+
+ async def main() -> None:
+ await client.pages.get_metadata(
+ page_id="63c720f9347c2139b248e552",
+ locale_id="65427cf400e02b306eaa04a0",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"pages/{jsonable_encoder(page_id)}"),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "locale": locale,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Page, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.get_metadata(page_id, locale_id=locale_id, request_options=request_options)
+ return _response.data
async def update_page_settings(
self,
page_id: str,
*,
- locale: typing.Optional[str] = None,
- request: Page,
+ locale_id: typing.Optional[str] = None,
+ title: typing.Optional[str] = OMIT,
+ slug: typing.Optional[str] = OMIT,
+ seo: typing.Optional[PageMetadataWriteSeo] = OMIT,
+ open_graph: typing.Optional[PageMetadataWriteOpenGraph] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
) -> Page:
"""
- Update Page-level metadata, including SEO and Open Graph fields. Required scope | `pages:write`
+ Update Page-level metadata, including SEO and Open Graph fields.
+
+ Required scope | `pages:write`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ title : typing.Optional[str]
+ Title for the page
+
+ slug : typing.Optional[str]
+ Slug for the page.
- Parameters:
- - page_id: str. Unique identifier for a Page
- - locale: typing.Optional[str]. Unique identifier for a specific locale. Applicable, when using localization.
+ **Note:** Updating slugs in secondary locales is only supported in Advanced and Enterprise localization add-on plans.
- - request: Page.
+ seo : typing.Optional[PageMetadataWriteSeo]
+ SEO-related fields for the Page
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- import datetime
+ open_graph : typing.Optional[PageMetadataWriteOpenGraph]
+ Open Graph fields for the Page
- from webflow import Page, PageOpenGraph, PageSeo
- from webflow.client import AsyncWebflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Page
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+ from webflow.resources.pages import (
+ PageMetadataWriteOpenGraph,
+ PageMetadataWriteSeo,
+ )
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.pages.update_page_settings(
- page_id="page_id",
- request=Page(
- id="6390c49774a71f0e3c1a08ee",
- site_id="6390c49674a71f84b51a08d8",
- title="Blog Categories Template",
- slug="detail_blog-category",
- parent_id="6419db964a9c435aa3af6251",
- collection_id="6390c49774a71f12831a08e3",
- created_on=datetime.datetime.fromisoformat(
- "2018-10-14 21:55:49+00:00",
- ),
- last_updated=datetime.datetime.fromisoformat(
- "2022-12-07 16:51:37+00:00",
- ),
- archived=False,
- draft=False,
- can_branch=True,
- is_members_only=False,
- seo=PageSeo(
- title="CoffeeStyle eCommerce - Webflow HTML website template",
- description="This Webflow template offers a quick start into an e-commerce / memberships site",
+
+
+ async def main() -> None:
+ await client.pages.update_page_settings(
+ page_id="63c720f9347c2139b248e552",
+ locale_id="65427cf400e02b306eaa04a0",
+ title="Guide to the Galaxy",
+ slug="guide-to-the-galaxy",
+ seo=PageMetadataWriteSeo(
+ 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.",
),
- open_graph=PageOpenGraph(
- title="CoffeeStyle eCommerce - Webflow HTML website template",
- title_copied=True,
- description="This Webflow template offers a quick start into an e-commerce / memberships site",
- description_copied=True,
+ open_graph=PageMetadataWriteOpenGraph(
+ title="Explore the Cosmos with The Ultimate Guide",
+ title_copied=False,
+ description="Dive deep into the mysteries of the universe with your guide to everything galactic.",
+ description_copied=False,
),
- ),
- )
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "PUT",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"pages/{jsonable_encoder(page_id)}"),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "locale": locale,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- json=jsonable_encoder(request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.update_page_settings(
+ page_id,
+ locale_id=locale_id,
+ title=title,
+ slug=slug,
+ seo=seo,
+ open_graph=open_graph,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Page, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
async def get_content(
self,
page_id: str,
*,
- locale: typing.Optional[str] = None,
+ locale_id: typing.Optional[str] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> Dom:
"""
- Get static content from a static page. 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 Required scope | `pages:read`
+ Get text and component instance content from a static page.
+
+ Localization
+
+ Required scope | `pages:read`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
- Parameters:
- - page_id: str. Unique identifier for a Page
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
- - locale: typing.Optional[str]. Unique identifier for a specific locale. Applicable, when using localization.
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Dom
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.pages.get_content(
- page_id="page_id",
- )
+
+
+ async def main() -> None:
+ await client.pages.get_content(
+ page_id="63c720f9347c2139b248e552",
+ locale_id="65427cf400e02b306eaa04a0",
+ limit=1,
+ offset=1,
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"pages/{jsonable_encoder(page_id)}/dom"),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "locale": locale,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.get_content(
+ page_id, locale_id=locale_id, limit=limit, offset=offset, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Dom, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
async def update_static_content(
self,
page_id: str,
*,
- locale: str,
- nodes: typing.Sequence[DomWriteNodesItem],
+ locale_id: str,
+ nodes: typing.Sequence[PageDomWriteNodesItem],
request_options: typing.Optional[RequestOptions] = None,
- ) -> Dom:
+ ) -> UpdateStaticContentResponse:
"""
- Update static content on a static page. This endpoint supports sending 1000 nodes per request. Required scope | `pages:write`
-
- Parameters:
- - page_id: str. Unique identifier for a Page
-
- - locale: str. The locale identifier.
-
- - nodes: typing.Sequence[DomWriteNodesItem].
-
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow import DomWriteNodesItem
- from webflow.client import AsyncWebflow
+ This endpoint updates content on a static page in **secondary locales**. It supports updating up to 1000 nodes in a single request.
+
+ Before making updates:
+ 1. Use the [get page content](/data/reference/pages-and-components/pages/get-content) endpoint to identify available content nodes and their types.
+ 2. If the page has component instances, retrieve the component's properties that you'll override using the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint.
+ 3. DOM elements may include a `data-w-id` attribute. This attribute is used by Webflow to maintain custom attributes and links across locales. Always include the original `data-w-id` value in your update requests to ensure consistent behavior across all locales.
+
+
+ This endpoint is specifically for localized pages. Ensure that the specified `localeId` is a valid **secondary locale** for the site otherwise the request will fail.
+
+
+ Required scope | `pages:write`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ locale_id : str
+ The locale identifier.
+
+ nodes : typing.Sequence[PageDomWriteNodesItem]
+ List of DOM Nodes with the new content that will be updated in each node.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ UpdateStaticContentResponse
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import (
+ AsyncWebflow,
+ ComponentInstanceNodePropertyOverridesWrite,
+ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem,
+ Select,
+ SelectNodeWriteChoicesItem,
+ SubmitButtonNodeWrite,
+ TextInputNodeWrite,
+ TextNodeWrite,
+ )
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.pages.update_static_content(
- page_id="page_id",
- locale="locale",
- nodes=[
- DomWriteNodesItem(
- node_id="guide-title-id",
- text="Hello world ",
- )
- ],
- )
+
+
+ async def main() -> None:
+ await client.pages.update_static_content(
+ page_id="63c720f9347c2139b248e552",
+ locale_id="localeId",
+ nodes=[
+ TextNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad623",
+ text="The Hitchhiker's Guide to the Galaxy ",
+ ),
+ TextNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad627",
+ text="Don't Panic! Always know where your towel is.
",
+ ),
+ Select(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad635",
+ choices=[
+ SelectNodeWriteChoicesItem(
+ value="choice-1",
+ text="First choice",
+ ),
+ SelectNodeWriteChoicesItem(
+ value="choice-2",
+ text="Second choice",
+ ),
+ ],
+ ),
+ TextInputNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad642",
+ placeholder="Enter something here...",
+ ),
+ SubmitButtonNodeWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad671",
+ value="Submit",
+ waiting_text="Submitting...",
+ ),
+ ComponentInstanceNodePropertyOverridesWrite(
+ node_id="a245c12d-995b-55ee-5ec7-aa36a6cad629",
+ property_overrides=[
+ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem(
+ property_id="7dd14c08-2e96-8d3d-2b19-b5c03642a0f0",
+ text="
Time is an illusion ",
+ ),
+ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem(
+ property_id="7dd14c08-2e96-8d3d-2b19-b5c03642a0f1",
+ text="Life, the Universe and Everything",
+ ),
+ ],
+ ),
+ ],
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"pages/{jsonable_encoder(page_id)}/dom"),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "locale": locale,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- json=jsonable_encoder({"nodes": nodes})
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder({"nodes": nodes}),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.update_static_content(
+ page_id, locale_id=locale_id, nodes=nodes, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Dom, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
+
+ @property
+ def scripts(self):
+ if self._scripts is None:
+ from .resources.scripts.client import AsyncScriptsClient # noqa: E402
+
+ self._scripts = AsyncScriptsClient(client_wrapper=self._client_wrapper)
+ return self._scripts
diff --git a/src/webflow/resources/pages/raw_client.py b/src/webflow/resources/pages/raw_client.py
new file mode 100644
index 0000000..1287d92
--- /dev/null
+++ b/src/webflow/resources/pages/raw_client.py
@@ -0,0 +1,1365 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from ...core.api_error import ApiError
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.http_response import AsyncHttpResponse, HttpResponse
+from ...core.jsonable_encoder import jsonable_encoder
+from ...core.parse_error import ParsingError
+from ...core.pydantic_utilities import parse_obj_as
+from ...core.request_options import RequestOptions
+from ...core.serialization import convert_and_respect_annotation_metadata
+from ...errors.bad_request_error import BadRequestError
+from ...errors.forbidden_error import ForbiddenError
+from ...errors.internal_server_error import InternalServerError
+from ...errors.not_found_error import NotFoundError
+from ...errors.too_many_requests_error import TooManyRequestsError
+from ...errors.unauthorized_error import UnauthorizedError
+from ...types.dom import Dom
+from ...types.error import Error
+from ...types.page import Page
+from ...types.page_list import PageList
+from .types.page_dom_write_nodes_item import PageDomWriteNodesItem
+from .types.page_metadata_write_open_graph import PageMetadataWriteOpenGraph
+from .types.page_metadata_write_seo import PageMetadataWriteSeo
+from .types.update_static_content_response import UpdateStaticContentResponse
+from pydantic import ValidationError
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RawPagesClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def list(
+ self,
+ site_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[PageList]:
+ """
+ List of all pages for a site.
+
+ Required scope | `pages:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[PageList]
+ Request was successful
+ """
+ _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,
+ "limit": limit,
+ "offset": offset,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ PageList,
+ parse_obj_as(
+ type_=PageList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def get_metadata(
+ self,
+ page_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[Page]:
+ """
+ Get metadata information for a single page.
+
+ Required scope | `pages:read`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Page]
+ Request was successful
+ """
+ _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,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Page,
+ parse_obj_as(
+ type_=Page, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def update_page_settings(
+ self,
+ page_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ title: typing.Optional[str] = OMIT,
+ slug: typing.Optional[str] = OMIT,
+ seo: typing.Optional[PageMetadataWriteSeo] = OMIT,
+ open_graph: typing.Optional[PageMetadataWriteOpenGraph] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[Page]:
+ """
+ Update Page-level metadata, including SEO and Open Graph fields.
+
+ Required scope | `pages:write`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ title : typing.Optional[str]
+ Title for the page
+
+ slug : typing.Optional[str]
+ Slug for the page.
+
+
+ **Note:** Updating slugs in secondary locales is only supported in Advanced and Enterprise localization add-on plans.
+
+ seo : typing.Optional[PageMetadataWriteSeo]
+ SEO-related fields for the Page
+
+ open_graph : typing.Optional[PageMetadataWriteOpenGraph]
+ Open Graph fields for the Page
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Page]
+ Request was successful
+ """
+ _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,
+ },
+ json={
+ "title": title,
+ "slug": slug,
+ "seo": convert_and_respect_annotation_metadata(
+ object_=seo, annotation=PageMetadataWriteSeo, direction="write"
+ ),
+ "openGraph": convert_and_respect_annotation_metadata(
+ object_=open_graph, annotation=PageMetadataWriteOpenGraph, direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Page,
+ parse_obj_as(
+ type_=Page, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def get_content(
+ self,
+ page_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[Dom]:
+ """
+ Get text and component instance content from a static page.
+
+ Localization
+
+ Required scope | `pages:read`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Dom]
+ Request was successful
+ """
+ _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,
+ "limit": limit,
+ "offset": offset,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Dom,
+ parse_obj_as(
+ type_=Dom, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def update_static_content(
+ self,
+ page_id: str,
+ *,
+ locale_id: str,
+ nodes: typing.Sequence[PageDomWriteNodesItem],
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[UpdateStaticContentResponse]:
+ """
+ This endpoint updates content on a static page in **secondary locales**. It supports updating up to 1000 nodes in a single request.
+
+ Before making updates:
+ 1. Use the [get page content](/data/reference/pages-and-components/pages/get-content) endpoint to identify available content nodes and their types.
+ 2. If the page has component instances, retrieve the component's properties that you'll override using the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint.
+ 3. DOM elements may include a `data-w-id` attribute. This attribute is used by Webflow to maintain custom attributes and links across locales. Always include the original `data-w-id` value in your update requests to ensure consistent behavior across all locales.
+
+
+ This endpoint is specifically for localized pages. Ensure that the specified `localeId` is a valid **secondary locale** for the site otherwise the request will fail.
+
+
+ Required scope | `pages:write`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ locale_id : str
+ The locale identifier.
+
+ nodes : typing.Sequence[PageDomWriteNodesItem]
+ List of DOM Nodes with the new content that will be updated in each node.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[UpdateStaticContentResponse]
+ Request was successful
+ """
+ _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,
+ },
+ json={
+ "nodes": convert_and_respect_annotation_metadata(
+ object_=nodes, annotation=typing.Sequence[PageDomWriteNodesItem], direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ UpdateStaticContentResponse,
+ parse_obj_as(
+ type_=UpdateStaticContentResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawPagesClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def list(
+ self,
+ site_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[PageList]:
+ """
+ List of all pages for a site.
+
+ Required scope | `pages:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[PageList]
+ Request was successful
+ """
+ _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,
+ "limit": limit,
+ "offset": offset,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ PageList,
+ parse_obj_as(
+ type_=PageList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def get_metadata(
+ self,
+ page_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[Page]:
+ """
+ Get metadata information for a single page.
+
+ Required scope | `pages:read`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Page]
+ Request was successful
+ """
+ _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,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Page,
+ parse_obj_as(
+ type_=Page, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def update_page_settings(
+ self,
+ page_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ title: typing.Optional[str] = OMIT,
+ slug: typing.Optional[str] = OMIT,
+ seo: typing.Optional[PageMetadataWriteSeo] = OMIT,
+ open_graph: typing.Optional[PageMetadataWriteOpenGraph] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[Page]:
+ """
+ Update Page-level metadata, including SEO and Open Graph fields.
+
+ Required scope | `pages:write`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ title : typing.Optional[str]
+ Title for the page
+
+ slug : typing.Optional[str]
+ Slug for the page.
+
+
+ **Note:** Updating slugs in secondary locales is only supported in Advanced and Enterprise localization add-on plans.
+
+ seo : typing.Optional[PageMetadataWriteSeo]
+ SEO-related fields for the Page
+
+ open_graph : typing.Optional[PageMetadataWriteOpenGraph]
+ Open Graph fields for the Page
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Page]
+ Request was successful
+ """
+ _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,
+ },
+ json={
+ "title": title,
+ "slug": slug,
+ "seo": convert_and_respect_annotation_metadata(
+ object_=seo, annotation=PageMetadataWriteSeo, direction="write"
+ ),
+ "openGraph": convert_and_respect_annotation_metadata(
+ object_=open_graph, annotation=PageMetadataWriteOpenGraph, direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Page,
+ parse_obj_as(
+ type_=Page, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def get_content(
+ self,
+ page_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[Dom]:
+ """
+ Get text and component instance content from a static page.
+
+ Localization
+
+ Required scope | `pages:read`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ locale_id : typing.Optional[str]
+ Unique identifier for a specific Locale.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Dom]
+ Request was successful
+ """
+ _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,
+ "limit": limit,
+ "offset": offset,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Dom,
+ parse_obj_as(
+ type_=Dom, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def update_static_content(
+ self,
+ page_id: str,
+ *,
+ locale_id: str,
+ nodes: typing.Sequence[PageDomWriteNodesItem],
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[UpdateStaticContentResponse]:
+ """
+ This endpoint updates content on a static page in **secondary locales**. It supports updating up to 1000 nodes in a single request.
+
+ Before making updates:
+ 1. Use the [get page content](/data/reference/pages-and-components/pages/get-content) endpoint to identify available content nodes and their types.
+ 2. If the page has component instances, retrieve the component's properties that you'll override using the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint.
+ 3. DOM elements may include a `data-w-id` attribute. This attribute is used by Webflow to maintain custom attributes and links across locales. Always include the original `data-w-id` value in your update requests to ensure consistent behavior across all locales.
+
+
+ This endpoint is specifically for localized pages. Ensure that the specified `localeId` is a valid **secondary locale** for the site otherwise the request will fail.
+
+
+ Required scope | `pages:write`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ locale_id : str
+ The locale identifier.
+
+ nodes : typing.Sequence[PageDomWriteNodesItem]
+ List of DOM Nodes with the new content that will be updated in each node.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[UpdateStaticContentResponse]
+ Request was successful
+ """
+ _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,
+ },
+ json={
+ "nodes": convert_and_respect_annotation_metadata(
+ object_=nodes, annotation=typing.Sequence[PageDomWriteNodesItem], direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ UpdateStaticContentResponse,
+ parse_obj_as(
+ type_=UpdateStaticContentResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/pages/resources/__init__.py b/src/webflow/resources/pages/resources/__init__.py
index 58b2c01..14bbc78 100644
--- a/src/webflow/resources/pages/resources/__init__.py
+++ b/src/webflow/resources/pages/resources/__init__.py
@@ -1,5 +1,34 @@
# This file was auto-generated by Fern from our API Definition.
-from . import scripts
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from . import scripts
+_dynamic_imports: typing.Dict[str, str] = {"scripts": ".scripts"}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
__all__ = ["scripts"]
diff --git a/src/webflow/resources/pages/resources/scripts/__init__.py b/src/webflow/resources/pages/resources/scripts/__init__.py
index f3ea265..5cde020 100644
--- a/src/webflow/resources/pages/resources/scripts/__init__.py
+++ b/src/webflow/resources/pages/resources/scripts/__init__.py
@@ -1,2 +1,4 @@
# This file was auto-generated by Fern from our API Definition.
+# isort: skip_file
+
diff --git a/src/webflow/resources/pages/resources/scripts/client.py b/src/webflow/resources/pages/resources/scripts/client.py
index db07c75..205dca5 100644
--- a/src/webflow/resources/pages/resources/scripts/client.py
+++ b/src/webflow/resources/pages/resources/scripts/client.py
@@ -1,25 +1,12 @@
# This file was auto-generated by Fern from our API Definition.
import typing
-import urllib.parse
-from json.decoder import JSONDecodeError
-from .....core.api_error import ApiError
from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from .....core.jsonable_encoder import jsonable_encoder
-from .....core.remove_none_from_dict import remove_none_from_dict
from .....core.request_options import RequestOptions
-from .....errors.bad_request_error import BadRequestError
-from .....errors.internal_server_error import InternalServerError
-from .....errors.not_found_error import NotFoundError
-from .....errors.too_many_requests_error import TooManyRequestsError
-from .....errors.unauthorized_error import UnauthorizedError
+from .....types.script_apply import ScriptApply
from .....types.script_apply_list import ScriptApplyList
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+from .raw_client import AsyncRawScriptsClient, RawScriptsClient
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
@@ -27,413 +14,337 @@
class ScriptsClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = RawScriptsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawScriptsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawScriptsClient
+ """
+ return self._raw_client
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. Required scope | `custom_code:read`
+ Get all scripts applied to a page.
- Parameters:
- - page_id: str. Unique identifier for a Page
+ Required scope | `custom_code:read`
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ScriptApplyList
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.pages.scripts.get_custom_code(
- page_id="page_id",
+ page_id="63c720f9347c2139b248e552",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"pages/{jsonable_encoder(page_id)}/custom_code"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(ScriptApplyList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.get_custom_code(page_id, request_options=request_options)
+ return _response.data
def upsert_custom_code(
- self, page_id: str, *, request: ScriptApplyList, request_options: typing.Optional[RequestOptions] = None
+ self,
+ page_id: str,
+ *,
+ scripts: typing.Optional[typing.Sequence[ScriptApply]] = OMIT,
+ last_updated: typing.Optional[str] = OMIT,
+ created_on: typing.Optional[str] = OMIT,
+ 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. Access to this endpoint requires a bearer token from a Data Client App. Required scope | `custom_code:write`
+ Apply registered scripts to a page. If you have multiple scripts your App needs to apply or maintain on a page, ensure they are always included in the request body for this endpoint. To remove individual scripts, simply call this endpoint without the script in the request body.
+
+
+ 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.
+
- Parameters:
- - page_id: str. Unique identifier for a Page
+ Required scope | `custom_code:write`
- - request: ScriptApplyList.
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow import ScriptApply, ScriptApplyList, ScriptApplyLocation
- from webflow.client import Webflow
+ 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.
+
+ Returns
+ -------
+ ScriptApplyList
+ Request was successful
+
+ Examples
+ --------
+ from webflow import ScriptApply, Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.pages.scripts.upsert_custom_code(
- page_id="page_id",
- request=ScriptApplyList(
- scripts=[
- ScriptApply(
- id="cms_slider",
- location=ScriptApplyLocation.HEADER,
- version="1.0.0",
- attributes={"my-attribute": "some-value"},
- ),
- ScriptApply(
- id="alert",
- location=ScriptApplyLocation.HEADER,
- version="0.0.1",
- ),
- ScriptApply(
- id="id",
- location=ScriptApplyLocation.HEADER,
- version="version",
- ),
- ],
- ),
+ page_id="63c720f9347c2139b248e552",
+ scripts=[
+ ScriptApply(
+ id="cms_slider",
+ location="header",
+ version="1.0.0",
+ attributes={"my-attribute": "some-value"},
+ ),
+ ScriptApply(
+ id="alert",
+ location="header",
+ version="0.0.1",
+ ),
+ ],
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "PUT",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"pages/{jsonable_encoder(page_id)}/custom_code"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.upsert_custom_code(
+ page_id, scripts=scripts, last_updated=last_updated, created_on=created_on, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(ScriptApplyList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
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. Access to this endpoint requires a bearer token from a Data Client App. Required scope | `custom_code:write`
+ Remove all scripts from a page applied by the App. This endpoint will not remove scripts from the site's registered scripts.
- Parameters:
- - page_id: str. Unique identifier for a Page
+ To remove individual scripts applied by the App, use the [Add/Update Custom Code](/data/reference/custom-code/custom-code-pages/upsert-custom-code) endpoint.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app).
+
+ Required scope | `custom_code:write`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.pages.scripts.delete_custom_code(
- page_id="page_id",
+ page_id="63c720f9347c2139b248e552",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "DELETE",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"pages/{jsonable_encoder(page_id)}/custom_code"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.delete_custom_code(page_id, request_options=request_options)
+ return _response.data
class AsyncScriptsClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = AsyncRawScriptsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawScriptsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawScriptsClient
+ """
+ return self._raw_client
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. Required scope | `custom_code:read`
+ Get all scripts applied to a page.
+
+ Required scope | `custom_code:read`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ScriptApplyList
+ Request was successful
- Parameters:
- - page_id: str. Unique identifier for a Page
+ Examples
+ --------
+ import asyncio
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.pages.scripts.get_custom_code(
- page_id="page_id",
- )
+
+
+ async def main() -> None:
+ await client.pages.scripts.get_custom_code(
+ page_id="63c720f9347c2139b248e552",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"pages/{jsonable_encoder(page_id)}/custom_code"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(ScriptApplyList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.get_custom_code(page_id, request_options=request_options)
+ return _response.data
async def upsert_custom_code(
- self, page_id: str, *, request: ScriptApplyList, request_options: typing.Optional[RequestOptions] = None
+ self,
+ page_id: str,
+ *,
+ scripts: typing.Optional[typing.Sequence[ScriptApply]] = OMIT,
+ last_updated: typing.Optional[str] = OMIT,
+ created_on: typing.Optional[str] = OMIT,
+ 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. Access to this endpoint requires a bearer token from a Data Client App. Required scope | `custom_code:write`
+ Apply registered scripts to a page. If you have multiple scripts your App needs to apply or maintain on a page, ensure they are always included in the request body for this endpoint. To remove individual scripts, simply call this endpoint without the script in the request body.
+
+
+ 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`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ scripts : typing.Optional[typing.Sequence[ScriptApply]]
+ A list of scripts applied to a Site or a Page
- Parameters:
- - page_id: str. Unique identifier for a Page
+ last_updated : typing.Optional[str]
+ Date when the Site's scripts were last updated
- - request: ScriptApplyList.
+ created_on : typing.Optional[str]
+ Date when the Site's scripts were created
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow import ScriptApply, ScriptApplyList, ScriptApplyLocation
- from webflow.client import AsyncWebflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ScriptApplyList
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow, ScriptApply
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.pages.scripts.upsert_custom_code(
- page_id="page_id",
- request=ScriptApplyList(
+
+
+ async def main() -> None:
+ await client.pages.scripts.upsert_custom_code(
+ page_id="63c720f9347c2139b248e552",
scripts=[
ScriptApply(
id="cms_slider",
- location=ScriptApplyLocation.HEADER,
+ location="header",
version="1.0.0",
attributes={"my-attribute": "some-value"},
),
ScriptApply(
id="alert",
- location=ScriptApplyLocation.HEADER,
+ location="header",
version="0.0.1",
),
- ScriptApply(
- id="id",
- location=ScriptApplyLocation.HEADER,
- version="version",
- ),
],
- ),
- )
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "PUT",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"pages/{jsonable_encoder(page_id)}/custom_code"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.upsert_custom_code(
+ page_id, scripts=scripts, last_updated=last_updated, created_on=created_on, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(ScriptApplyList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
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. Access to this endpoint requires a bearer token from a Data Client App. Required scope | `custom_code:write`
+ Remove all scripts from a page applied by the App. This endpoint will not remove scripts from the site's registered scripts.
+
+ To remove individual scripts applied by the App, use the [Add/Update Custom Code](/data/reference/custom-code/custom-code-pages/upsert-custom-code) endpoint.
+
+ Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app).
+
+ Required scope | `custom_code:write`
- Parameters:
- - page_id: str. Unique identifier for a Page
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.pages.scripts.delete_custom_code(
- page_id="page_id",
- )
+
+
+ async def main() -> None:
+ await client.pages.scripts.delete_custom_code(
+ page_id="63c720f9347c2139b248e552",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "DELETE",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"pages/{jsonable_encoder(page_id)}/custom_code"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.delete_custom_code(page_id, request_options=request_options)
+ return _response.data
diff --git a/src/webflow/resources/pages/resources/scripts/raw_client.py b/src/webflow/resources/pages/resources/scripts/raw_client.py
new file mode 100644
index 0000000..6a71dd8
--- /dev/null
+++ b/src/webflow/resources/pages/resources/scripts/raw_client.py
@@ -0,0 +1,716 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from .....core.api_error import ApiError
+from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .....core.http_response import AsyncHttpResponse, HttpResponse
+from .....core.jsonable_encoder import jsonable_encoder
+from .....core.parse_error import ParsingError
+from .....core.pydantic_utilities import parse_obj_as
+from .....core.request_options import RequestOptions
+from .....core.serialization import convert_and_respect_annotation_metadata
+from .....errors.bad_request_error import BadRequestError
+from .....errors.conflict_error import ConflictError
+from .....errors.internal_server_error import InternalServerError
+from .....errors.not_found_error import NotFoundError
+from .....errors.too_many_requests_error import TooManyRequestsError
+from .....errors.unauthorized_error import UnauthorizedError
+from .....types.error import Error
+from .....types.script_apply import ScriptApply
+from .....types.script_apply_list import ScriptApplyList
+from pydantic import ValidationError
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RawScriptsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def get_custom_code(
+ self, page_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[ScriptApplyList]:
+ """
+ Get all scripts applied to a page.
+
+ Required scope | `custom_code:read`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[ScriptApplyList]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ScriptApplyList,
+ parse_obj_as(
+ type_=ScriptApplyList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def upsert_custom_code(
+ self,
+ page_id: str,
+ *,
+ scripts: typing.Optional[typing.Sequence[ScriptApply]] = OMIT,
+ last_updated: typing.Optional[str] = OMIT,
+ created_on: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[ScriptApplyList]:
+ """
+ Apply registered scripts to a page. If you have multiple scripts your App needs to apply or maintain on a page, ensure they are always included in the request body for this endpoint. To remove individual scripts, simply call this endpoint without the script in the request body.
+
+
+ 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`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ 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.
+
+ Returns
+ -------
+ HttpResponse[ScriptApplyList]
+ Request was successful
+ """
+ _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(
+ object_=scripts, annotation=typing.Sequence[ScriptApply], direction="write"
+ ),
+ "lastUpdated": last_updated,
+ "createdOn": created_on,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ScriptApplyList,
+ parse_obj_as(
+ type_=ScriptApplyList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def delete_custom_code(
+ self, page_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[None]:
+ """
+ Remove all scripts from a page applied by the App. This endpoint will not remove scripts from the site's registered scripts.
+
+ To remove individual scripts applied by the App, use the [Add/Update Custom Code](/data/reference/custom-code/custom-code-pages/upsert-custom-code) endpoint.
+
+ Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app).
+
+ Required scope | `custom_code:write`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[None]
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return HttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawScriptsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def get_custom_code(
+ self, page_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[ScriptApplyList]:
+ """
+ Get all scripts applied to a page.
+
+ Required scope | `custom_code:read`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[ScriptApplyList]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ScriptApplyList,
+ parse_obj_as(
+ type_=ScriptApplyList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def upsert_custom_code(
+ self,
+ page_id: str,
+ *,
+ scripts: typing.Optional[typing.Sequence[ScriptApply]] = OMIT,
+ last_updated: typing.Optional[str] = OMIT,
+ created_on: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[ScriptApplyList]:
+ """
+ Apply registered scripts to a page. If you have multiple scripts your App needs to apply or maintain on a page, ensure they are always included in the request body for this endpoint. To remove individual scripts, simply call this endpoint without the script in the request body.
+
+
+ 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`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ 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.
+
+ Returns
+ -------
+ AsyncHttpResponse[ScriptApplyList]
+ Request was successful
+ """
+ _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(
+ object_=scripts, annotation=typing.Sequence[ScriptApply], direction="write"
+ ),
+ "lastUpdated": last_updated,
+ "createdOn": created_on,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ScriptApplyList,
+ parse_obj_as(
+ type_=ScriptApplyList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def delete_custom_code(
+ self, page_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[None]:
+ """
+ Remove all scripts from a page applied by the App. This endpoint will not remove scripts from the site's registered scripts.
+
+ To remove individual scripts applied by the App, use the [Add/Update Custom Code](/data/reference/custom-code/custom-code-pages/upsert-custom-code) endpoint.
+
+ Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app).
+
+ Required scope | `custom_code:write`
+
+ Parameters
+ ----------
+ page_id : str
+ Unique identifier for a Page
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return AsyncHttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/pages/types/__init__.py b/src/webflow/resources/pages/types/__init__.py
index fdefa12..e606a89 100644
--- a/src/webflow/resources/pages/types/__init__.py
+++ b/src/webflow/resources/pages/types/__init__.py
@@ -1,5 +1,42 @@
# This file was auto-generated by Fern from our API Definition.
-from .dom_write_nodes_item import DomWriteNodesItem
+# isort: skip_file
-__all__ = ["DomWriteNodesItem"]
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .page_dom_write_nodes_item import PageDomWriteNodesItem
+ from .page_metadata_write_open_graph import PageMetadataWriteOpenGraph
+ from .page_metadata_write_seo import PageMetadataWriteSeo
+ from .update_static_content_response import UpdateStaticContentResponse
+_dynamic_imports: typing.Dict[str, str] = {
+ "PageDomWriteNodesItem": ".page_dom_write_nodes_item",
+ "PageMetadataWriteOpenGraph": ".page_metadata_write_open_graph",
+ "PageMetadataWriteSeo": ".page_metadata_write_seo",
+ "UpdateStaticContentResponse": ".update_static_content_response",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = ["PageDomWriteNodesItem", "PageMetadataWriteOpenGraph", "PageMetadataWriteSeo", "UpdateStaticContentResponse"]
diff --git a/src/webflow/resources/pages/types/dom_write_nodes_item.py b/src/webflow/resources/pages/types/dom_write_nodes_item.py
deleted file mode 100644
index 36f7d9b..0000000
--- a/src/webflow/resources/pages/types/dom_write_nodes_item.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import datetime as dt
-import typing
-
-from ....core.datetime_utils import serialize_datetime
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class DomWriteNodesItem(pydantic.BaseModel):
- node_id: str = pydantic.Field(alias="nodeId", description="Node UUID")
- text: str = pydantic.Field(description="HTML content of the node")
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
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
new file mode 100644
index 0000000..8c562cf
--- /dev/null
+++ b/src/webflow/resources/pages/types/page_dom_write_nodes_item.py
@@ -0,0 +1,19 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from ....types.component_instance_node_property_overrides_write import ComponentInstanceNodePropertyOverridesWrite
+from ....types.search_button_node_write import SearchButtonNodeWrite
+from ....types.select import Select
+from ....types.submit_button_node_write import SubmitButtonNodeWrite
+from ....types.text_input_node_write import TextInputNodeWrite
+from ....types.text_node_write import TextNodeWrite
+
+PageDomWriteNodesItem = typing.Union[
+ TextNodeWrite,
+ ComponentInstanceNodePropertyOverridesWrite,
+ Select,
+ TextInputNodeWrite,
+ SubmitButtonNodeWrite,
+ SearchButtonNodeWrite,
+]
diff --git a/src/webflow/resources/pages/types/page_metadata_write_open_graph.py b/src/webflow/resources/pages/types/page_metadata_write_open_graph.py
new file mode 100644
index 0000000..0a80301
--- /dev/null
+++ b/src/webflow/resources/pages/types/page_metadata_write_open_graph.py
@@ -0,0 +1,47 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ....core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ....core.serialization import FieldMetadata
+
+
+class PageMetadataWriteOpenGraph(UniversalBaseModel):
+ """
+ Open Graph fields for the Page
+ """
+
+ title: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The title supplied to Open Graph annotations
+ """
+
+ title_copied: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="titleCopied"),
+ pydantic.Field(alias="titleCopied", description="Indicates the Open Graph title was copied from the SEO title"),
+ ] = None
+ description: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The description supplied to Open Graph annotations
+ """
+
+ description_copied: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="descriptionCopied"),
+ pydantic.Field(
+ alias="descriptionCopied",
+ description="Indicates the Open Graph description was copied from the SEO description",
+ ),
+ ] = 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/pages/types/page_metadata_write_seo.py b/src/webflow/resources/pages/types/page_metadata_write_seo.py
new file mode 100644
index 0000000..a03a778
--- /dev/null
+++ b/src/webflow/resources/pages/types/page_metadata_write_seo.py
@@ -0,0 +1,31 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ....core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class PageMetadataWriteSeo(UniversalBaseModel):
+ """
+ SEO-related fields for the Page
+ """
+
+ title: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The Page title shown in search engine results
+ """
+
+ description: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The Page description shown in search engine results
+ """
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/resources/pages/types/update_static_content_response.py b/src/webflow/resources/pages/types/update_static_content_response.py
new file mode 100644
index 0000000..99e93aa
--- /dev/null
+++ b/src/webflow/resources/pages/types/update_static_content_response.py
@@ -0,0 +1,22 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ....core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class UpdateStaticContentResponse(UniversalBaseModel):
+ errors: typing.List[str] = pydantic.Field()
+ """
+ A list of error messages, if any.
+ """
+
+ 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/__init__.py b/src/webflow/resources/products/__init__.py
index d1569c5..fe1618a 100644
--- a/src/webflow/resources/products/__init__.py
+++ b/src/webflow/resources/products/__init__.py
@@ -1,31 +1,38 @@
# This file was auto-generated by Fern from our API Definition.
-from .types import (
- ProductSkuCreateProduct,
- ProductSkuCreateProductFieldData,
- ProductSkuCreateProductFieldDataEcProductType,
- ProductSkuCreateProductFieldDataTaxCategory,
- ProductSkuCreateSku,
- ProductSkuCreateSkuFieldData,
- ProductSkuCreateSkuFieldDataCompareAtPrice,
- ProductSkuCreateSkuFieldDataEcSkuBillingMethod,
- ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlan,
- ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlanInterval,
- ProductSkuCreateSkuFieldDataPrice,
- ProductsCreateSkuResponse,
-)
-
-__all__ = [
- "ProductSkuCreateProduct",
- "ProductSkuCreateProductFieldData",
- "ProductSkuCreateProductFieldDataEcProductType",
- "ProductSkuCreateProductFieldDataTaxCategory",
- "ProductSkuCreateSku",
- "ProductSkuCreateSkuFieldData",
- "ProductSkuCreateSkuFieldDataCompareAtPrice",
- "ProductSkuCreateSkuFieldDataEcSkuBillingMethod",
- "ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlan",
- "ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlanInterval",
- "ProductSkuCreateSkuFieldDataPrice",
- "ProductsCreateSkuResponse",
-]
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .types import ProductSkuCreateProduct, ProductSkuCreateSku, ProductsCreateSkuResponse
+_dynamic_imports: typing.Dict[str, str] = {
+ "ProductSkuCreateProduct": ".types",
+ "ProductSkuCreateSku": ".types",
+ "ProductsCreateSkuResponse": ".types",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = ["ProductSkuCreateProduct", "ProductSkuCreateSku", "ProductsCreateSkuResponse"]
diff --git a/src/webflow/resources/products/client.py b/src/webflow/resources/products/client.py
index 4d7180a..c20d5cf 100644
--- a/src/webflow/resources/products/client.py
+++ b/src/webflow/resources/products/client.py
@@ -1,288 +1,259 @@
# This file was auto-generated by Fern from our API Definition.
import typing
-import urllib.parse
-from json.decoder import JSONDecodeError
-from ...core.api_error import ApiError
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from ...core.jsonable_encoder import jsonable_encoder
-from ...core.remove_none_from_dict import remove_none_from_dict
from ...core.request_options import RequestOptions
-from ...errors.bad_request_error import BadRequestError
-from ...errors.conflict_error import ConflictError
-from ...errors.forbidden_error import ForbiddenError
-from ...errors.internal_server_error import InternalServerError
-from ...errors.not_found_error import NotFoundError
-from ...errors.too_many_requests_error import TooManyRequestsError
-from ...errors.unauthorized_error import UnauthorizedError
from ...types.product import Product
from ...types.product_and_sk_us import ProductAndSkUs
from ...types.product_and_sk_us_list import ProductAndSkUsList
from ...types.publish_status import PublishStatus
from ...types.sku import Sku
+from .raw_client import AsyncRawProductsClient, RawProductsClient
from .types.product_sku_create_product import ProductSkuCreateProduct
from .types.product_sku_create_sku import ProductSkuCreateSku
from .types.products_create_sku_response import ProductsCreateSkuResponse
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
class ProductsClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = RawProductsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawProductsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawProductsClient
+ """
+ return self._raw_client
def list(
self,
site_id: str,
*,
- offset: typing.Optional[float] = None,
- limit: typing.Optional[float] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> ProductAndSkUsList:
"""
- 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.
+ 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`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
- - offset: typing.Optional[float]. Offset used for pagination if the results have more than limit records
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - limit: typing.Optional[float]. Maximum number of records to be returned (max limit: 100)
+ Returns
+ -------
+ ProductAndSkUsList
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.products.list(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
+ offset=1,
+ limit=1,
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/products"
- ),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "offset": offset,
- "limit": limit,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(ProductAndSkUsList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.list(site_id, offset=offset, limit=limit, request_options=request_options)
+ return _response.data
def create(
self,
site_id: str,
*,
+ product: ProductSkuCreateProduct,
+ sku: ProductSkuCreateSku,
publish_status: typing.Optional[PublishStatus] = OMIT,
- product: typing.Optional[ProductSkuCreateProduct] = OMIT,
- sku: typing.Optional[ProductSkuCreateSku] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
) -> ProductAndSkUs:
"""
- Creating a new Product involves creating both a Product and a SKU, since a Product Item has to have, at minimum, a single SKU.
+ Create a new ecommerce product and defaultSKU. A product, at minimum, must have a single SKU.
- In order to create a Product with multiple SKUs - for example a T-shirt in sizes small, medium and large - you'll need to create `sku-properties`. In our T-shirt example, a single `sku-property` would be Color. Within that property, we'll need to list out the various colors a T-shirt could be as an array of `enum` values: `royal-blue`, `crimson-red`, and `forrest-green`.
+ 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)
- Once, you've created a Product and its `sku-properties` with `enum` values, you can create your 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
-
- Upon creation, the default product type will be `Advanced`. The product type is used to determine which Product and SKU fields are shown to users in the `Designer` and the `Editor`. Setting it to `Advanced` ensures that all Product and SKU fields will be shown.
+ 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`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ product : ProductSkuCreateProduct
+
+ sku : ProductSkuCreateSku
- - publish_status: typing.Optional[PublishStatus].
+ publish_status : typing.Optional[PublishStatus]
- - product: typing.Optional[ProductSkuCreateProduct]. The Product Object
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - sku: typing.Optional[ProductSkuCreateSku]. The SKU object
+ Returns
+ -------
+ ProductAndSkUs
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Examples
+ --------
+ 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="site_id",
- )
- """
- _request: typing.Dict[str, typing.Any] = {}
- if publish_status is not OMIT:
- _request["publishStatus"] = publish_status.value if publish_status is not None else None
- if product is not OMIT:
- _request["product"] = product
- if sku is not OMIT:
- _request["sku"] = sku
- _response = self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/products"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
+ 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",
+ ),
+ ],
+ ),
+ ],
+ ),
),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
+ 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",
+ ),
),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(ProductAndSkUs, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ """
+ _response = self._raw_client.create(
+ site_id, product=product, sku=sku, publish_status=publish_status, request_options=request_options
+ )
+ return _response.data
def get(
self, site_id: str, product_id: str, *, request_options: typing.Optional[RequestOptions] = None
) -> ProductAndSkUs:
"""
- Retrieve a single product by its id. All of its SKUs will also be retrieved.
+ Retrieve a single product by its ID. All of its SKUs will also be
+ retrieved.
Required scope | `ecommerce:read`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ product_id : str
+ Unique identifier for a Product
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - product_id: str. Unique identifier for a Product
+ Returns
+ -------
+ ProductAndSkUs
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.products.get(
- site_id="site_id",
- product_id="product_id",
+ site_id="580e63e98c9a982ac9b8b741",
+ product_id="580e63fc8c9a982ac9b8b745",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(ProductAndSkUs, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.get(site_id, product_id, request_options=request_options)
+ return _response.data
def update(
self,
@@ -290,195 +261,114 @@ def update(
product_id: str,
*,
publish_status: typing.Optional[PublishStatus] = OMIT,
- product: Product,
+ product: typing.Optional[Product] = OMIT,
+ sku: typing.Optional[Sku] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
) -> Product:
"""
- Updating an existing Product will set the product type to `Advanced`. The product type is used to determine which Product and SKU fields are shown to users in the `Designer` and the `Editor`. Setting it to `Advanced` ensures that all Product and SKU fields will be shown. The product type can be edited in the `Designer` or the `Editor`.
+ Update an existing Product.
+
+ Updating an existing Product will set the product type to `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer.
Required scope | `ecommerce:write`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- - product_id: str. Unique identifier for a Product
+ product_id : str
+ Unique identifier for a Product
- - publish_status: typing.Optional[PublishStatus].
+ publish_status : typing.Optional[PublishStatus]
- - product: Product.
+ product : typing.Optional[Product]
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- import datetime
+ sku : typing.Optional[Sku]
- from webflow import (
- Product,
- ProductFieldData,
- SkuPropertyList,
- SkuPropertyListEnumItem,
- )
- from webflow.client import Webflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Product
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.products.update(
- site_id="site_id",
- product_id="product_id",
- product=Product(
- id="580e63fc8c9a982ac9b8b745",
- 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",
- ),
- is_archived=False,
- is_draft=False,
- field_data=ProductFieldData(
- name="T-Shirt",
- slug="t-shirt",
- description="A plain cotton t-shirt.",
- shippable=True,
- sku_properties=[
- SkuPropertyList(
- id="color",
- name="Color",
- enum=[
- SkuPropertyListEnumItem(
- id="royal-blue",
- name="Royal Blue",
- slug="royal-blue",
- ),
- SkuPropertyListEnumItem(
- id="crimson-red",
- name="Crimson Red",
- slug="crimson-red",
- ),
- SkuPropertyListEnumItem(
- id="forrest-green",
- name="name",
- slug="slug",
- ),
- SkuPropertyListEnumItem(
- id="id",
- name="name",
- slug="slug",
- ),
- ],
- ),
- SkuPropertyList(
- id="Color",
- name="Color",
- enum=[
- SkuPropertyListEnumItem(
- id="id",
- name="name",
- slug="slug",
- )
- ],
- ),
- ],
- ),
- ),
+ site_id="580e63e98c9a982ac9b8b741",
+ product_id="580e63fc8c9a982ac9b8b745",
)
"""
- _request: typing.Dict[str, typing.Any] = {"product": product}
- if publish_status is not OMIT:
- _request["publishStatus"] = publish_status.value if publish_status is not None else None
- _response = self._client_wrapper.httpx_client.request(
- "PATCH",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.update(
+ site_id,
+ product_id,
+ publish_status=publish_status,
+ product=product,
+ sku=sku,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Product, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
def create_sku(
self,
site_id: str,
product_id: str,
*,
- publish_status: typing.Optional[PublishStatus] = OMIT,
skus: typing.Sequence[Sku],
+ publish_status: typing.Optional[PublishStatus] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
) -> ProductsCreateSkuResponse:
"""
- Create additional SKUs to cover every variant of your Product. The Default SKU already counts as one of the variants.
+ 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 additional SKUs will set the product type to `Advanced` for the product associated with the SKUs. The product type is used to determine which Product and SKU fields are shown to users in the `Designer` and the `Editor`. Setting it to `Advanced` ensures that all Product and SKU fields will be shown. The product type can be edited in the `Designer` or the `Editor`.
+ 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`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ product_id : str
+ Unique identifier for a Product
- - product_id: str. Unique identifier for a Product
+ skus : typing.Sequence[Sku]
+ An array of the SKU data your are adding
- - publish_status: typing.Optional[PublishStatus].
+ publish_status : typing.Optional[PublishStatus]
- - skus: typing.Sequence[Sku]. An array of the SKU data your are adding
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
+ Returns
+ -------
+ ProductsCreateSkuResponse
+ Request was successful
+
+ Examples
+ --------
import datetime
- from webflow import Sku, SkuFieldData, SkuFieldDataPrice
- from webflow.client import Webflow
+ from webflow import Sku, SkuFieldData, SkuFieldDataPrice, Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.products.create_sku(
- site_id="site_id",
- product_id="product_id",
+ site_id="580e63e98c9a982ac9b8b741",
+ product_id="580e63fc8c9a982ac9b8b745",
skus=[
Sku(
- id="580e63fc8c9a982ac9b8b745",
+ id="66072fb71b89448912e2681c",
+ cms_locale_id="653ad57de882f528b32e810e",
last_published=datetime.datetime.fromisoformat(
"2023-03-17 18:47:35+00:00",
),
@@ -489,69 +379,22 @@ def create_sku(
"2023-03-17 18:47:35+00:00",
),
field_data=SkuFieldData(
- name="Blue T-shirt",
- slug="t-shirt-blue",
+ name="Colorful T-shirt - Default",
+ slug="colorful-t-shirt-default",
price=SkuFieldDataPrice(
- value=100.0,
+ value=2499.0,
unit="USD",
+ currency="USD",
),
- quantity=10.0,
),
)
],
)
"""
- _request: typing.Dict[str, typing.Any] = {"skus": skus}
- if publish_status is not OMIT:
- _request["publishStatus"] = publish_status.value if publish_status is not None else None
- _response = self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}/skus",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.create_sku(
+ site_id, product_id, skus=skus, publish_status=publish_status, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(ProductsCreateSkuResponse, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
def update_sku(
self,
@@ -559,42 +402,56 @@ def update_sku(
product_id: str,
sku_id: str,
*,
- publish_status: typing.Optional[PublishStatus] = OMIT,
sku: Sku,
+ publish_status: typing.Optional[PublishStatus] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
) -> Sku:
"""
- Updating an existing SKU will set the product type to `Advanced` for the product associated with the SKU. The product type is used to determine which Product and SKU fields are shown to users in the `Designer` and the `Editor`. Setting it to `Advanced` ensures that all Product and SKU fields will be shown. The product type can be edited in the `Designer` or the `Editor`.
+ Update a specified SKU.
+
+ Updating an existing SKU will set the Product type to `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer.
Required scope | `ecommerce:write`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ product_id : str
+ Unique identifier for a Product
+
+ sku_id : str
+ Unique identifier for a SKU
- - product_id: str. Unique identifier for a Product
+ sku : Sku
- - sku_id: str. Unique identifier for a SKU
+ publish_status : typing.Optional[PublishStatus]
- - publish_status: typing.Optional[PublishStatus].
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - sku: Sku.
+ Returns
+ -------
+ Sku
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
+ Examples
+ --------
import datetime
- from webflow import Sku, SkuFieldData, SkuFieldDataPrice
- from webflow.client import Webflow
+ from webflow import Sku, SkuFieldData, SkuFieldDataPrice, Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.products.update_sku(
- site_id="site_id",
- product_id="product_id",
- sku_id="sku_id",
+ site_id="580e63e98c9a982ac9b8b741",
+ product_id="580e63fc8c9a982ac9b8b745",
+ sku_id="5e8518516e147040726cc415",
sku=Sku(
- id="580e63fc8c9a982ac9b8b745",
+ id="66072fb71b89448912e2681c",
+ cms_locale_id="653ad57de882f528b32e810e",
last_published=datetime.datetime.fromisoformat(
"2023-03-17 18:47:35+00:00",
),
@@ -605,319 +462,283 @@ def update_sku(
"2023-03-17 18:47:35+00:00",
),
field_data=SkuFieldData(
- name="Blue T-shirt",
- slug="t-shirt-blue",
+ name="Colorful T-shirt - Default",
+ slug="colorful-t-shirt-default",
price=SkuFieldDataPrice(
- value=100.0,
+ value=2499.0,
unit="USD",
+ currency="USD",
),
- quantity=10.0,
),
),
)
"""
- _request: typing.Dict[str, typing.Any] = {"sku": sku}
- if publish_status is not OMIT:
- _request["publishStatus"] = publish_status.value if publish_status is not None else None
- _response = self._client_wrapper.httpx_client.request(
- "PATCH",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}/skus/{jsonable_encoder(sku_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.update_sku(
+ site_id, product_id, sku_id, sku=sku, publish_status=publish_status, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Sku, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
class AsyncProductsClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = AsyncRawProductsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawProductsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawProductsClient
+ """
+ return self._raw_client
async def list(
self,
site_id: str,
*,
- offset: typing.Optional[float] = None,
- limit: typing.Optional[float] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> ProductAndSkUsList:
"""
- 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.
+ 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`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - offset: typing.Optional[float]. Offset used for pagination if the results have more than limit records
+ Returns
+ -------
+ ProductAndSkUsList
+ Request was successful
- - limit: typing.Optional[float]. Maximum number of records to be returned (max limit: 100)
+ Examples
+ --------
+ import asyncio
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.products.list(
- site_id="site_id",
- )
+
+
+ async def main() -> None:
+ await client.products.list(
+ site_id="580e63e98c9a982ac9b8b741",
+ offset=1,
+ limit=1,
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/products"
- ),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "offset": offset,
- "limit": limit,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(ProductAndSkUsList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.list(site_id, offset=offset, limit=limit, request_options=request_options)
+ return _response.data
async def create(
self,
site_id: str,
*,
+ product: ProductSkuCreateProduct,
+ sku: ProductSkuCreateSku,
publish_status: typing.Optional[PublishStatus] = OMIT,
- product: typing.Optional[ProductSkuCreateProduct] = OMIT,
- sku: typing.Optional[ProductSkuCreateSku] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
) -> ProductAndSkUs:
"""
- Creating a new Product involves creating both a Product and a SKU, since a Product Item has to have, at minimum, a single SKU.
-
- In order to create a Product with multiple SKUs - for example a T-shirt in sizes small, medium and large - you'll need to create `sku-properties`. In our T-shirt example, a single `sku-property` would be Color. Within that property, we'll need to list out the various colors a T-shirt could be as an array of `enum` values: `royal-blue`, `crimson-red`, and `forrest-green`.
+ Create a new ecommerce product and defaultSKU. A product, at minimum, must have a single SKU.
- Once, you've created a Product and its `sku-properties` with `enum` values, you can create your 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
+ 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`. The product type is used to determine which Product and SKU fields are shown to users in the `Designer` and the `Editor`. Setting it to `Advanced` ensures that all Product and SKU fields will be shown.
+ 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`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ product : ProductSkuCreateProduct
+
+ sku : ProductSkuCreateSku
- - publish_status: typing.Optional[PublishStatus].
+ publish_status : typing.Optional[PublishStatus]
- - product: typing.Optional[ProductSkuCreateProduct]. The Product Object
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - sku: typing.Optional[ProductSkuCreateSku]. The SKU object
+ Returns
+ -------
+ ProductAndSkUs
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Examples
+ --------
+ import asyncio
+
+ from webflow import (
+ AsyncWebflow,
+ ProductFieldData,
+ SkuFieldData,
+ SkuFieldDataPrice,
+ SkuPropertyList,
+ SkuPropertyListEnumItem,
+ )
+ from webflow.resources.products import (
+ ProductSkuCreateProduct,
+ ProductSkuCreateSku,
+ )
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.products.create(
- site_id="site_id",
- )
+
+
+ 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",
+ ),
+ ),
+ )
+
+
+ asyncio.run(main())
"""
- _request: typing.Dict[str, typing.Any] = {}
- if publish_status is not OMIT:
- _request["publishStatus"] = publish_status.value if publish_status is not None else None
- if product is not OMIT:
- _request["product"] = product
- if sku is not OMIT:
- _request["sku"] = sku
- _response = await self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/products"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.create(
+ site_id, product=product, sku=sku, publish_status=publish_status, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(ProductAndSkUs, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
async def get(
self, site_id: str, product_id: str, *, request_options: typing.Optional[RequestOptions] = None
) -> ProductAndSkUs:
"""
- Retrieve a single product by its id. All of its SKUs will also be retrieved.
+ Retrieve a single product by its ID. All of its SKUs will also be
+ retrieved.
Required scope | `ecommerce:read`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ product_id : str
+ Unique identifier for a Product
- - product_id: str. Unique identifier for a Product
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Returns
+ -------
+ ProductAndSkUs
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.products.get(
- site_id="site_id",
- product_id="product_id",
- )
+
+
+ async def main() -> None:
+ await client.products.get(
+ site_id="580e63e98c9a982ac9b8b741",
+ product_id="580e63fc8c9a982ac9b8b745",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(ProductAndSkUs, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.get(site_id, product_id, request_options=request_options)
+ return _response.data
async def update(
self,
@@ -925,268 +746,155 @@ async def update(
product_id: str,
*,
publish_status: typing.Optional[PublishStatus] = OMIT,
- product: Product,
+ product: typing.Optional[Product] = OMIT,
+ sku: typing.Optional[Sku] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
) -> Product:
"""
- Updating an existing Product will set the product type to `Advanced`. The product type is used to determine which Product and SKU fields are shown to users in the `Designer` and the `Editor`. Setting it to `Advanced` ensures that all Product and SKU fields will be shown. The product type can be edited in the `Designer` or the `Editor`.
+ Update an existing Product.
+
+ Updating an existing Product will set the product type to `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer.
Required scope | `ecommerce:write`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- - product_id: str. Unique identifier for a Product
+ product_id : str
+ Unique identifier for a Product
- - publish_status: typing.Optional[PublishStatus].
+ publish_status : typing.Optional[PublishStatus]
- - product: Product.
+ product : typing.Optional[Product]
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- import datetime
+ sku : typing.Optional[Sku]
- from webflow import (
- Product,
- ProductFieldData,
- SkuPropertyList,
- SkuPropertyListEnumItem,
- )
- from webflow.client import AsyncWebflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Product
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.products.update(
- site_id="site_id",
- product_id="product_id",
- product=Product(
- id="580e63fc8c9a982ac9b8b745",
- 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",
- ),
- is_archived=False,
- is_draft=False,
- field_data=ProductFieldData(
- name="T-Shirt",
- slug="t-shirt",
- description="A plain cotton t-shirt.",
- shippable=True,
- sku_properties=[
- SkuPropertyList(
- id="color",
- name="Color",
- enum=[
- SkuPropertyListEnumItem(
- id="royal-blue",
- name="Royal Blue",
- slug="royal-blue",
- ),
- SkuPropertyListEnumItem(
- id="crimson-red",
- name="Crimson Red",
- slug="crimson-red",
- ),
- SkuPropertyListEnumItem(
- id="forrest-green",
- name="name",
- slug="slug",
- ),
- SkuPropertyListEnumItem(
- id="id",
- name="name",
- slug="slug",
- ),
- ],
- ),
- SkuPropertyList(
- id="Color",
- name="Color",
- enum=[
- SkuPropertyListEnumItem(
- id="id",
- name="name",
- slug="slug",
- )
- ],
- ),
- ],
- ),
- ),
- )
+
+
+ async def main() -> None:
+ await client.products.update(
+ site_id="580e63e98c9a982ac9b8b741",
+ product_id="580e63fc8c9a982ac9b8b745",
+ )
+
+
+ asyncio.run(main())
"""
- _request: typing.Dict[str, typing.Any] = {"product": product}
- if publish_status is not OMIT:
- _request["publishStatus"] = publish_status.value if publish_status is not None else None
- _response = await self._client_wrapper.httpx_client.request(
- "PATCH",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.update(
+ site_id,
+ product_id,
+ publish_status=publish_status,
+ product=product,
+ sku=sku,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Product, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
async def create_sku(
self,
site_id: str,
product_id: str,
*,
- publish_status: typing.Optional[PublishStatus] = OMIT,
skus: typing.Sequence[Sku],
+ publish_status: typing.Optional[PublishStatus] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
) -> ProductsCreateSkuResponse:
"""
- Create additional SKUs to cover every variant of your Product. The Default SKU already counts as one of the variants.
+ 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 additional SKUs will set the product type to `Advanced` for the product associated with the SKUs. The product type is used to determine which Product and SKU fields are shown to users in the `Designer` and the `Editor`. Setting it to `Advanced` ensures that all Product and SKU fields will be shown. The product type can be edited in the `Designer` or the `Editor`.
+ 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`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ product_id : str
+ Unique identifier for a Product
- - product_id: str. Unique identifier for a Product
+ skus : typing.Sequence[Sku]
+ An array of the SKU data your are adding
- - publish_status: typing.Optional[PublishStatus].
+ publish_status : typing.Optional[PublishStatus]
- - skus: typing.Sequence[Sku]. An array of the SKU data your are adding
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
+ Returns
+ -------
+ ProductsCreateSkuResponse
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
import datetime
- from webflow import Sku, SkuFieldData, SkuFieldDataPrice
- from webflow.client import AsyncWebflow
+ from webflow import AsyncWebflow, Sku, SkuFieldData, SkuFieldDataPrice
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.products.create_sku(
- site_id="site_id",
- product_id="product_id",
- skus=[
- Sku(
- id="580e63fc8c9a982ac9b8b745",
- 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="Blue T-shirt",
- slug="t-shirt-blue",
- price=SkuFieldDataPrice(
- value=100.0,
- unit="USD",
+
+
+ async def main() -> None:
+ await 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",
),
- quantity=10.0,
- ),
- )
- ],
- )
+ 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",
+ ),
+ ),
+ )
+ ],
+ )
+
+
+ asyncio.run(main())
"""
- _request: typing.Dict[str, typing.Any] = {"skus": skus}
- if publish_status is not OMIT:
- _request["publishStatus"] = publish_status.value if publish_status is not None else None
- _response = await self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}/skus",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.create_sku(
+ site_id, product_id, skus=skus, publish_status=publish_status, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(ProductsCreateSkuResponse, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
async def update_sku(
self,
@@ -1194,111 +902,85 @@ async def update_sku(
product_id: str,
sku_id: str,
*,
- publish_status: typing.Optional[PublishStatus] = OMIT,
sku: Sku,
+ publish_status: typing.Optional[PublishStatus] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
) -> Sku:
"""
- Updating an existing SKU will set the product type to `Advanced` for the product associated with the SKU. The product type is used to determine which Product and SKU fields are shown to users in the `Designer` and the `Editor`. Setting it to `Advanced` ensures that all Product and SKU fields will be shown. The product type can be edited in the `Designer` or the `Editor`.
+ Update a specified SKU.
+
+ Updating an existing SKU will set the Product type to `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer.
Required scope | `ecommerce:write`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ product_id : str
+ Unique identifier for a Product
+
+ sku_id : str
+ Unique identifier for a SKU
- - product_id: str. Unique identifier for a Product
+ sku : Sku
- - sku_id: str. Unique identifier for a SKU
+ publish_status : typing.Optional[PublishStatus]
- - publish_status: typing.Optional[PublishStatus].
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - sku: Sku.
+ Returns
+ -------
+ Sku
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
+ Examples
+ --------
+ import asyncio
import datetime
- from webflow import Sku, SkuFieldData, SkuFieldDataPrice
- from webflow.client import AsyncWebflow
+ from webflow import AsyncWebflow, Sku, SkuFieldData, SkuFieldDataPrice
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.products.update_sku(
- site_id="site_id",
- product_id="product_id",
- sku_id="sku_id",
- sku=Sku(
- id="580e63fc8c9a982ac9b8b745",
- 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="Blue T-shirt",
- slug="t-shirt-blue",
- price=SkuFieldDataPrice(
- value=100.0,
- unit="USD",
+
+
+ async def main() -> None:
+ await client.products.update_sku(
+ site_id="580e63e98c9a982ac9b8b741",
+ product_id="580e63fc8c9a982ac9b8b745",
+ sku_id="5e8518516e147040726cc415",
+ sku=Sku(
+ id="66072fb71b89448912e2681c",
+ cms_locale_id="653ad57de882f528b32e810e",
+ last_published=datetime.datetime.fromisoformat(
+ "2023-03-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",
+ ),
),
- quantity=10.0,
),
- ),
- )
+ )
+
+
+ asyncio.run(main())
"""
- _request: typing.Dict[str, typing.Any] = {"sku": sku}
- if publish_status is not OMIT:
- _request["publishStatus"] = publish_status.value if publish_status is not None else None
- _response = await self._client_wrapper.httpx_client.request(
- "PATCH",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}/skus/{jsonable_encoder(sku_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.update_sku(
+ site_id, product_id, sku_id, sku=sku, publish_status=publish_status, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Sku, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
diff --git a/src/webflow/resources/products/raw_client.py b/src/webflow/resources/products/raw_client.py
new file mode 100644
index 0000000..e7b0965
--- /dev/null
+++ b/src/webflow/resources/products/raw_client.py
@@ -0,0 +1,1791 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from ...core.api_error import ApiError
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.http_response import AsyncHttpResponse, HttpResponse
+from ...core.jsonable_encoder import jsonable_encoder
+from ...core.parse_error import ParsingError
+from ...core.pydantic_utilities import parse_obj_as
+from ...core.request_options import RequestOptions
+from ...core.serialization import convert_and_respect_annotation_metadata
+from ...errors.bad_request_error import BadRequestError
+from ...errors.conflict_error import ConflictError
+from ...errors.forbidden_error import ForbiddenError
+from ...errors.internal_server_error import InternalServerError
+from ...errors.not_found_error import NotFoundError
+from ...errors.too_many_requests_error import TooManyRequestsError
+from ...errors.unauthorized_error import UnauthorizedError
+from ...types.error import Error
+from ...types.product import Product
+from ...types.product_and_sk_us import ProductAndSkUs
+from ...types.product_and_sk_us_list import ProductAndSkUsList
+from ...types.publish_status import PublishStatus
+from ...types.sku import Sku
+from .types.product_sku_create_product import ProductSkuCreateProduct
+from .types.product_sku_create_sku import ProductSkuCreateSku
+from .types.products_create_sku_response import ProductsCreateSkuResponse
+from pydantic import ValidationError
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RawProductsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def list(
+ self,
+ site_id: str,
+ *,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[ProductAndSkUsList]:
+ """
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[ProductAndSkUsList]
+ Request was successful
+ """
+ _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,
+ "limit": limit,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ProductAndSkUsList,
+ parse_obj_as(
+ type_=ProductAndSkUsList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def create(
+ self,
+ site_id: str,
+ *,
+ product: ProductSkuCreateProduct,
+ sku: ProductSkuCreateSku,
+ publish_status: typing.Optional[PublishStatus] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[ProductAndSkUs]:
+ """
+ Create a new ecommerce product and defaultSKU. A product, at minimum, must have a single SKU.
+
+ To create a product with multiple SKUs:
+ - First, create a list of `sku-properties`, also known as [product options](https://help.webflow.com/hc/en-us/articles/33961334531347-Create-product-options-and-variants). For example, a T-shirt product may have a "color" `sku-property`, with a list of enum values: red, yellow, and blue, another `sku-property` may be "size", with a list of enum values: small, medium, and large.
+ - Once, a product is created with a list of `sku-properties`, Webflow will create a **default SKU**, which is always a combination of the first `enum` values of each `sku-property`. (e.g. Small - Red - T-Shirt)
+ - After creation, you can create additional SKUs for the product, using the [Create SKUs endpoint.](/data/reference/ecommerce/products/create-sku)
+
+ Upon creation, the default product type will be `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer.
+
+ Required scope | `ecommerce:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ product : ProductSkuCreateProduct
+
+ sku : ProductSkuCreateSku
+
+ publish_status : typing.Optional[PublishStatus]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[ProductAndSkUs]
+ Request was successful
+ """
+ _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=ProductSkuCreateProduct, direction="write"
+ ),
+ "sku": convert_and_respect_annotation_metadata(
+ object_=sku, annotation=ProductSkuCreateSku, direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ProductAndSkUs,
+ parse_obj_as(
+ type_=ProductAndSkUs, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def get(
+ self, site_id: str, product_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[ProductAndSkUs]:
+ """
+ Retrieve a single product by its ID. All of its SKUs will also be
+ retrieved.
+
+ Required scope | `ecommerce:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ product_id : str
+ Unique identifier for a Product
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[ProductAndSkUs]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ProductAndSkUs,
+ parse_obj_as(
+ type_=ProductAndSkUs, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def update(
+ self,
+ site_id: str,
+ product_id: str,
+ *,
+ publish_status: typing.Optional[PublishStatus] = OMIT,
+ product: typing.Optional[Product] = OMIT,
+ sku: typing.Optional[Sku] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[Product]:
+ """
+ Update an existing Product.
+
+ Updating an existing Product will set the product type to `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer.
+
+ Required scope | `ecommerce:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ product_id : str
+ Unique identifier for a Product
+
+ publish_status : typing.Optional[PublishStatus]
+
+ product : typing.Optional[Product]
+
+ sku : typing.Optional[Sku]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Product]
+ Request was successful
+ """
+ _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,
+ "product": convert_and_respect_annotation_metadata(
+ object_=product, annotation=Product, direction="write"
+ ),
+ "sku": convert_and_respect_annotation_metadata(object_=sku, annotation=Sku, direction="write"),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Product,
+ parse_obj_as(
+ type_=Product, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def create_sku(
+ self,
+ site_id: str,
+ product_id: str,
+ *,
+ skus: typing.Sequence[Sku],
+ publish_status: typing.Optional[PublishStatus] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[ProductsCreateSkuResponse]:
+ """
+ Create additional SKUs to manage every [option and variant of your Product.](https://help.webflow.com/hc/en-us/articles/33961334531347-Create-product-options-and-variants)
+
+ Creating SKUs through the API will set the product type to `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer.
+
+ Required scope | `ecommerce:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ product_id : str
+ Unique identifier for a Product
+
+ 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.
+
+ Returns
+ -------
+ HttpResponse[ProductsCreateSkuResponse]
+ Request was successful
+ """
+ _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,
+ "skus": convert_and_respect_annotation_metadata(
+ object_=skus, annotation=typing.Sequence[Sku], direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ProductsCreateSkuResponse,
+ parse_obj_as(
+ type_=ProductsCreateSkuResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def update_sku(
+ self,
+ site_id: str,
+ product_id: str,
+ sku_id: str,
+ *,
+ sku: Sku,
+ publish_status: typing.Optional[PublishStatus] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[Sku]:
+ """
+ Update a specified SKU.
+
+ Updating an existing SKU will set the Product type to `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer.
+
+ Required scope | `ecommerce:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ product_id : str
+ Unique identifier for a Product
+
+ sku_id : str
+ Unique identifier for a SKU
+
+ sku : Sku
+
+ publish_status : typing.Optional[PublishStatus]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Sku]
+ Request was successful
+ """
+ _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,
+ "sku": convert_and_respect_annotation_metadata(object_=sku, annotation=Sku, direction="write"),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Sku,
+ parse_obj_as(
+ type_=Sku, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawProductsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def list(
+ self,
+ site_id: str,
+ *,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[ProductAndSkUsList]:
+ """
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[ProductAndSkUsList]
+ Request was successful
+ """
+ _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,
+ "limit": limit,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ProductAndSkUsList,
+ parse_obj_as(
+ type_=ProductAndSkUsList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def create(
+ self,
+ site_id: str,
+ *,
+ product: ProductSkuCreateProduct,
+ sku: ProductSkuCreateSku,
+ publish_status: typing.Optional[PublishStatus] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[ProductAndSkUs]:
+ """
+ Create a new ecommerce product and defaultSKU. A product, at minimum, must have a single SKU.
+
+ To create a product with multiple SKUs:
+ - First, create a list of `sku-properties`, also known as [product options](https://help.webflow.com/hc/en-us/articles/33961334531347-Create-product-options-and-variants). For example, a T-shirt product may have a "color" `sku-property`, with a list of enum values: red, yellow, and blue, another `sku-property` may be "size", with a list of enum values: small, medium, and large.
+ - Once, a product is created with a list of `sku-properties`, Webflow will create a **default SKU**, which is always a combination of the first `enum` values of each `sku-property`. (e.g. Small - Red - T-Shirt)
+ - After creation, you can create additional SKUs for the product, using the [Create SKUs endpoint.](/data/reference/ecommerce/products/create-sku)
+
+ Upon creation, the default product type will be `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer.
+
+ Required scope | `ecommerce:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ product : ProductSkuCreateProduct
+
+ sku : ProductSkuCreateSku
+
+ publish_status : typing.Optional[PublishStatus]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[ProductAndSkUs]
+ Request was successful
+ """
+ _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=ProductSkuCreateProduct, direction="write"
+ ),
+ "sku": convert_and_respect_annotation_metadata(
+ object_=sku, annotation=ProductSkuCreateSku, direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ProductAndSkUs,
+ parse_obj_as(
+ type_=ProductAndSkUs, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def get(
+ self, site_id: str, product_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[ProductAndSkUs]:
+ """
+ Retrieve a single product by its ID. All of its SKUs will also be
+ retrieved.
+
+ Required scope | `ecommerce:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ product_id : str
+ Unique identifier for a Product
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[ProductAndSkUs]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ProductAndSkUs,
+ parse_obj_as(
+ type_=ProductAndSkUs, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def update(
+ self,
+ site_id: str,
+ product_id: str,
+ *,
+ publish_status: typing.Optional[PublishStatus] = OMIT,
+ product: typing.Optional[Product] = OMIT,
+ sku: typing.Optional[Sku] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[Product]:
+ """
+ Update an existing Product.
+
+ Updating an existing Product will set the product type to `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer.
+
+ Required scope | `ecommerce:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ product_id : str
+ Unique identifier for a Product
+
+ publish_status : typing.Optional[PublishStatus]
+
+ product : typing.Optional[Product]
+
+ sku : typing.Optional[Sku]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Product]
+ Request was successful
+ """
+ _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,
+ "product": convert_and_respect_annotation_metadata(
+ object_=product, annotation=Product, direction="write"
+ ),
+ "sku": convert_and_respect_annotation_metadata(object_=sku, annotation=Sku, direction="write"),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Product,
+ parse_obj_as(
+ type_=Product, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def create_sku(
+ self,
+ site_id: str,
+ product_id: str,
+ *,
+ skus: typing.Sequence[Sku],
+ publish_status: typing.Optional[PublishStatus] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[ProductsCreateSkuResponse]:
+ """
+ Create additional SKUs to manage every [option and variant of your Product.](https://help.webflow.com/hc/en-us/articles/33961334531347-Create-product-options-and-variants)
+
+ Creating SKUs through the API will set the product type to `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer.
+
+ Required scope | `ecommerce:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ product_id : str
+ Unique identifier for a Product
+
+ 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.
+
+ Returns
+ -------
+ AsyncHttpResponse[ProductsCreateSkuResponse]
+ Request was successful
+ """
+ _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,
+ "skus": convert_and_respect_annotation_metadata(
+ object_=skus, annotation=typing.Sequence[Sku], direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ProductsCreateSkuResponse,
+ parse_obj_as(
+ type_=ProductsCreateSkuResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def update_sku(
+ self,
+ site_id: str,
+ product_id: str,
+ sku_id: str,
+ *,
+ sku: Sku,
+ publish_status: typing.Optional[PublishStatus] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[Sku]:
+ """
+ Update a specified SKU.
+
+ Updating an existing SKU will set the Product type to `Advanced`, which ensures all Product and SKU fields will be shown to users in the Designer.
+
+ Required scope | `ecommerce:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ product_id : str
+ Unique identifier for a Product
+
+ sku_id : str
+ Unique identifier for a SKU
+
+ sku : Sku
+
+ publish_status : typing.Optional[PublishStatus]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Sku]
+ Request was successful
+ """
+ _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,
+ "sku": convert_and_respect_annotation_metadata(object_=sku, annotation=Sku, direction="write"),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Sku,
+ parse_obj_as(
+ type_=Sku, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/products/types/__init__.py b/src/webflow/resources/products/types/__init__.py
index 55ac9d6..909ffe5 100644
--- a/src/webflow/resources/products/types/__init__.py
+++ b/src/webflow/resources/products/types/__init__.py
@@ -1,33 +1,40 @@
# This file was auto-generated by Fern from our API Definition.
-from .product_sku_create_product import ProductSkuCreateProduct
-from .product_sku_create_product_field_data import ProductSkuCreateProductFieldData
-from .product_sku_create_product_field_data_ec_product_type import ProductSkuCreateProductFieldDataEcProductType
-from .product_sku_create_product_field_data_tax_category import ProductSkuCreateProductFieldDataTaxCategory
-from .product_sku_create_sku import ProductSkuCreateSku
-from .product_sku_create_sku_field_data import ProductSkuCreateSkuFieldData
-from .product_sku_create_sku_field_data_compare_at_price import ProductSkuCreateSkuFieldDataCompareAtPrice
-from .product_sku_create_sku_field_data_ec_sku_billing_method import ProductSkuCreateSkuFieldDataEcSkuBillingMethod
-from .product_sku_create_sku_field_data_ec_sku_subscription_plan import (
- ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlan,
-)
-from .product_sku_create_sku_field_data_ec_sku_subscription_plan_interval import (
- ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlanInterval,
-)
-from .product_sku_create_sku_field_data_price import ProductSkuCreateSkuFieldDataPrice
-from .products_create_sku_response import ProductsCreateSkuResponse
-
-__all__ = [
- "ProductSkuCreateProduct",
- "ProductSkuCreateProductFieldData",
- "ProductSkuCreateProductFieldDataEcProductType",
- "ProductSkuCreateProductFieldDataTaxCategory",
- "ProductSkuCreateSku",
- "ProductSkuCreateSkuFieldData",
- "ProductSkuCreateSkuFieldDataCompareAtPrice",
- "ProductSkuCreateSkuFieldDataEcSkuBillingMethod",
- "ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlan",
- "ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlanInterval",
- "ProductSkuCreateSkuFieldDataPrice",
- "ProductsCreateSkuResponse",
-]
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .product_sku_create_product import ProductSkuCreateProduct
+ from .product_sku_create_sku import ProductSkuCreateSku
+ from .products_create_sku_response import ProductsCreateSkuResponse
+_dynamic_imports: typing.Dict[str, str] = {
+ "ProductSkuCreateProduct": ".product_sku_create_product",
+ "ProductSkuCreateSku": ".product_sku_create_sku",
+ "ProductsCreateSkuResponse": ".products_create_sku_response",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = ["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
index 6e410b8..d35d712 100644
--- a/src/webflow/resources/products/types/product_sku_create_product.py
+++ b/src/webflow/resources/products/types/product_sku_create_product.py
@@ -1,50 +1,24 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ....core.datetime_utils import serialize_datetime
-from .product_sku_create_product_field_data import ProductSkuCreateProductFieldData
+import pydantic
+import typing_extensions
+from ....core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ....core.serialization import FieldMetadata
+from ....types.product_field_data import ProductFieldData
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+class ProductSkuCreateProduct(UniversalBaseModel):
+ field_data: typing_extensions.Annotated[
+ typing.Optional[ProductFieldData], FieldMetadata(alias="fieldData"), pydantic.Field(alias="fieldData")
+ ] = None
-class ProductSkuCreateProduct(pydantic.BaseModel):
- """
- The Product Object
- """
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
- id: typing.Optional[str] = pydantic.Field(default=None, description="Unique identifier for the Product")
- last_published: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastPublished", default=None, description="The date the Product was last published"
- )
- last_updated: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastUpdated", default=None, description="The date the Product was last updated"
- )
- created_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="createdOn", default=None, description="The date the Product was created"
- )
- is_archived: typing.Optional[bool] = pydantic.Field(
- alias="isArchived", default=None, description="Boolean determining if the Product is set to archived"
- )
- is_draft: typing.Optional[bool] = pydantic.Field(
- alias="isDraft", default=None, description="Boolean determining if the Product is set to draft"
- )
- field_data: typing.Optional[ProductSkuCreateProductFieldData] = pydantic.Field(alias="fieldData", default=None)
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/resources/products/types/product_sku_create_product_field_data.py b/src/webflow/resources/products/types/product_sku_create_product_field_data.py
deleted file mode 100644
index 2748896..0000000
--- a/src/webflow/resources/products/types/product_sku_create_product_field_data.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import datetime as dt
-import typing
-
-from ....core.datetime_utils import serialize_datetime
-from ....types.sku_property_list import SkuPropertyList
-from .product_sku_create_product_field_data_ec_product_type import ProductSkuCreateProductFieldDataEcProductType
-from .product_sku_create_product_field_data_tax_category import ProductSkuCreateProductFieldDataTaxCategory
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class ProductSkuCreateProductFieldData(pydantic.BaseModel):
- name: str = pydantic.Field(description="Name of the Product")
- slug: str = pydantic.Field(description="URL structure of the Product in your site.")
- description: typing.Optional[str] = pydantic.Field(default=None, description="A description of your product")
- shippable: typing.Optional[bool] = pydantic.Field(
- default=None, description="Boolean determining if the Product is shippable"
- )
- sku_properties: typing.Optional[typing.List[SkuPropertyList]] = pydantic.Field(
- alias="sku-properties", default=None, description="Variant types to include in SKUs"
- )
- categories: typing.Optional[typing.List[typing.Any]] = pydantic.Field(
- default=None, description="The categories your product belongs to."
- )
- tax_category: typing.Optional[ProductSkuCreateProductFieldDataTaxCategory] = pydantic.Field(
- alias="tax-category", default=None, description="Product tax class"
- )
- ec_product_type: typing.Optional[ProductSkuCreateProductFieldDataEcProductType] = pydantic.Field(
- alias="ec-product-type",
- default=None,
- description='Product types. Enums reflect the following values in order: Physical, Digital, Service, Advanced"',
- )
- additional_properties: typing.Optional[typing.Any] = pydantic.Field(alias="additionalProperties", default=None)
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
diff --git a/src/webflow/resources/products/types/product_sku_create_product_field_data_ec_product_type.py b/src/webflow/resources/products/types/product_sku_create_product_field_data_ec_product_type.py
deleted file mode 100644
index 05f521c..0000000
--- a/src/webflow/resources/products/types/product_sku_create_product_field_data_ec_product_type.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import enum
-import typing
-
-T_Result = typing.TypeVar("T_Result")
-
-
-class ProductSkuCreateProductFieldDataEcProductType(str, enum.Enum):
- """
- Product types. Enums reflect the following values in order: Physical, Digital, Service, Advanced"
- """
-
- FF_42_FEE_0113744_F_693_A_764_E_3431_A_9_CC_2 = "ff42fee0113744f693a764e3431a9cc2"
- F_22027_DB_68002190_AEF_89_A_4_A_2_B_7_AC_8_A_1 = "f22027db68002190aef89a4a2b7ac8a1"
- C_599_E_43_B_1_A_1_C_34_D_5_A_323_AEDF_75_D_3_ADF_6 = "c599e43b1a1c34d5a323aedf75d3adf6"
- B_6_CCC_1830_DB_4_B_1_BABEB_06_A_9_AC_5_F_6_DD_76 = "b6ccc1830db4b1babeb06a9ac5f6dd76"
-
- def visit(
- self,
- ff_42_fee_0113744_f_693_a_764_e_3431_a_9_cc_2: typing.Callable[[], T_Result],
- f_22027_db_68002190_aef_89_a_4_a_2_b_7_ac_8_a_1: typing.Callable[[], T_Result],
- c_599_e_43_b_1_a_1_c_34_d_5_a_323_aedf_75_d_3_adf_6: typing.Callable[[], T_Result],
- b_6_ccc_1830_db_4_b_1_babeb_06_a_9_ac_5_f_6_dd_76: typing.Callable[[], T_Result],
- ) -> T_Result:
- if self is ProductSkuCreateProductFieldDataEcProductType.FF_42_FEE_0113744_F_693_A_764_E_3431_A_9_CC_2:
- return ff_42_fee_0113744_f_693_a_764_e_3431_a_9_cc_2()
- if self is ProductSkuCreateProductFieldDataEcProductType.F_22027_DB_68002190_AEF_89_A_4_A_2_B_7_AC_8_A_1:
- return f_22027_db_68002190_aef_89_a_4_a_2_b_7_ac_8_a_1()
- if self is ProductSkuCreateProductFieldDataEcProductType.C_599_E_43_B_1_A_1_C_34_D_5_A_323_AEDF_75_D_3_ADF_6:
- return c_599_e_43_b_1_a_1_c_34_d_5_a_323_aedf_75_d_3_adf_6()
- if self is ProductSkuCreateProductFieldDataEcProductType.B_6_CCC_1830_DB_4_B_1_BABEB_06_A_9_AC_5_F_6_DD_76:
- return b_6_ccc_1830_db_4_b_1_babeb_06_a_9_ac_5_f_6_dd_76()
diff --git a/src/webflow/resources/products/types/product_sku_create_product_field_data_tax_category.py b/src/webflow/resources/products/types/product_sku_create_product_field_data_tax_category.py
deleted file mode 100644
index a2eb210..0000000
--- a/src/webflow/resources/products/types/product_sku_create_product_field_data_tax_category.py
+++ /dev/null
@@ -1,133 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import enum
-import typing
-
-T_Result = typing.TypeVar("T_Result")
-
-
-class ProductSkuCreateProductFieldDataTaxCategory(str, enum.Enum):
- """
- Product tax class
- """
-
- STANDARD_TAXABLE = "standard-taxable"
- STANDARD_EXEMPT = "standard-exempt"
- BOOKS_RELIGIOUS = "books-religious"
- BOOKS_TEXTBOOK = "books-textbook"
- CLOTHING = "clothing"
- CLOTHING_SWIMWEAR = "clothing-swimwear"
- DIGITAL_GOODS = "digital-goods"
- DIGITAL_SERVICE = "digital-service"
- DRUGS_NON_PRESCRIPTION = "drugs-non-prescription"
- DRUGS_PRESCRIPTION = "drugs-prescription"
- FOOD_BOTTLED_WATER = "food-bottled-water"
- FOOD_CANDY = "food-candy"
- FOOD_GROCERIES = "food-groceries"
- FOOD_PREPARED = "food-prepared"
- FOOD_SODA = "food-soda"
- FOOD_SUPPLEMENTS = "food-supplements"
- MAGAZINE_INDIVIDUAL = "magazine-individual"
- MAGAZINE_SUBSCRIPTION = "magazine-subscription"
- SERVICE_ADMISSION = "service-admission"
- SERVICE_ADVERTISING = "service-advertising"
- SERVICE_DRY_CLEANING = "service-dry-cleaning"
- SERVICE_HAIRDRESSING = "service-hairdressing"
- SERVICE_INSTALLATION = "service-installation"
- SERVICE_MISCELLANEOUS = "service-miscellaneous"
- SERVICE_PARKING = "service-parking"
- SERVICE_PRINTING = "service-printing"
- SERVICE_PROFESSIONAL = "service-professional"
- SERVICE_REPAIR = "service-repair"
- SERVICE_TRAINING = "service-training"
-
- def visit(
- self,
- standard_taxable: typing.Callable[[], T_Result],
- standard_exempt: typing.Callable[[], T_Result],
- books_religious: typing.Callable[[], T_Result],
- books_textbook: typing.Callable[[], T_Result],
- clothing: typing.Callable[[], T_Result],
- clothing_swimwear: typing.Callable[[], T_Result],
- digital_goods: typing.Callable[[], T_Result],
- digital_service: typing.Callable[[], T_Result],
- drugs_non_prescription: typing.Callable[[], T_Result],
- drugs_prescription: typing.Callable[[], T_Result],
- food_bottled_water: typing.Callable[[], T_Result],
- food_candy: typing.Callable[[], T_Result],
- food_groceries: typing.Callable[[], T_Result],
- food_prepared: typing.Callable[[], T_Result],
- food_soda: typing.Callable[[], T_Result],
- food_supplements: typing.Callable[[], T_Result],
- magazine_individual: typing.Callable[[], T_Result],
- magazine_subscription: typing.Callable[[], T_Result],
- service_admission: typing.Callable[[], T_Result],
- service_advertising: typing.Callable[[], T_Result],
- service_dry_cleaning: typing.Callable[[], T_Result],
- service_hairdressing: typing.Callable[[], T_Result],
- service_installation: typing.Callable[[], T_Result],
- service_miscellaneous: typing.Callable[[], T_Result],
- service_parking: typing.Callable[[], T_Result],
- service_printing: typing.Callable[[], T_Result],
- service_professional: typing.Callable[[], T_Result],
- service_repair: typing.Callable[[], T_Result],
- service_training: typing.Callable[[], T_Result],
- ) -> T_Result:
- if self is ProductSkuCreateProductFieldDataTaxCategory.STANDARD_TAXABLE:
- return standard_taxable()
- if self is ProductSkuCreateProductFieldDataTaxCategory.STANDARD_EXEMPT:
- return standard_exempt()
- if self is ProductSkuCreateProductFieldDataTaxCategory.BOOKS_RELIGIOUS:
- return books_religious()
- if self is ProductSkuCreateProductFieldDataTaxCategory.BOOKS_TEXTBOOK:
- return books_textbook()
- if self is ProductSkuCreateProductFieldDataTaxCategory.CLOTHING:
- return clothing()
- if self is ProductSkuCreateProductFieldDataTaxCategory.CLOTHING_SWIMWEAR:
- return clothing_swimwear()
- if self is ProductSkuCreateProductFieldDataTaxCategory.DIGITAL_GOODS:
- return digital_goods()
- if self is ProductSkuCreateProductFieldDataTaxCategory.DIGITAL_SERVICE:
- return digital_service()
- if self is ProductSkuCreateProductFieldDataTaxCategory.DRUGS_NON_PRESCRIPTION:
- return drugs_non_prescription()
- if self is ProductSkuCreateProductFieldDataTaxCategory.DRUGS_PRESCRIPTION:
- return drugs_prescription()
- if self is ProductSkuCreateProductFieldDataTaxCategory.FOOD_BOTTLED_WATER:
- return food_bottled_water()
- if self is ProductSkuCreateProductFieldDataTaxCategory.FOOD_CANDY:
- return food_candy()
- if self is ProductSkuCreateProductFieldDataTaxCategory.FOOD_GROCERIES:
- return food_groceries()
- if self is ProductSkuCreateProductFieldDataTaxCategory.FOOD_PREPARED:
- return food_prepared()
- if self is ProductSkuCreateProductFieldDataTaxCategory.FOOD_SODA:
- return food_soda()
- if self is ProductSkuCreateProductFieldDataTaxCategory.FOOD_SUPPLEMENTS:
- return food_supplements()
- if self is ProductSkuCreateProductFieldDataTaxCategory.MAGAZINE_INDIVIDUAL:
- return magazine_individual()
- if self is ProductSkuCreateProductFieldDataTaxCategory.MAGAZINE_SUBSCRIPTION:
- return magazine_subscription()
- if self is ProductSkuCreateProductFieldDataTaxCategory.SERVICE_ADMISSION:
- return service_admission()
- if self is ProductSkuCreateProductFieldDataTaxCategory.SERVICE_ADVERTISING:
- return service_advertising()
- if self is ProductSkuCreateProductFieldDataTaxCategory.SERVICE_DRY_CLEANING:
- return service_dry_cleaning()
- if self is ProductSkuCreateProductFieldDataTaxCategory.SERVICE_HAIRDRESSING:
- return service_hairdressing()
- if self is ProductSkuCreateProductFieldDataTaxCategory.SERVICE_INSTALLATION:
- return service_installation()
- if self is ProductSkuCreateProductFieldDataTaxCategory.SERVICE_MISCELLANEOUS:
- return service_miscellaneous()
- if self is ProductSkuCreateProductFieldDataTaxCategory.SERVICE_PARKING:
- return service_parking()
- if self is ProductSkuCreateProductFieldDataTaxCategory.SERVICE_PRINTING:
- return service_printing()
- if self is ProductSkuCreateProductFieldDataTaxCategory.SERVICE_PROFESSIONAL:
- return service_professional()
- if self is ProductSkuCreateProductFieldDataTaxCategory.SERVICE_REPAIR:
- return service_repair()
- if self is ProductSkuCreateProductFieldDataTaxCategory.SERVICE_TRAINING:
- return service_training()
diff --git a/src/webflow/resources/products/types/product_sku_create_sku.py b/src/webflow/resources/products/types/product_sku_create_sku.py
index 2877e3c..838e778 100644
--- a/src/webflow/resources/products/types/product_sku_create_sku.py
+++ b/src/webflow/resources/products/types/product_sku_create_sku.py
@@ -1,46 +1,24 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ....core.datetime_utils import serialize_datetime
-from .product_sku_create_sku_field_data import ProductSkuCreateSkuFieldData
+import pydantic
+import typing_extensions
+from ....core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ....core.serialization import FieldMetadata
+from ....types.sku_field_data import SkuFieldData
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+class ProductSkuCreateSku(UniversalBaseModel):
+ field_data: typing_extensions.Annotated[
+ typing.Optional[SkuFieldData], FieldMetadata(alias="fieldData"), pydantic.Field(alias="fieldData")
+ ] = None
-class ProductSkuCreateSku(pydantic.BaseModel):
- """
- The SKU object
- """
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
- id: typing.Optional[str] = pydantic.Field(default=None, description="Unique identifier for the Product")
- last_published: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastPublished", default=None, description="The date the Product was last published"
- )
- last_updated: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastUpdated", default=None, description="The date the Product was last updated"
- )
- created_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="createdOn", default=None, description="The date the Product was created"
- )
- field_data: typing.Optional[ProductSkuCreateSkuFieldData] = pydantic.Field(
- alias="fieldData", default=None, description="Standard and Custom fields for a SKU"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/resources/products/types/product_sku_create_sku_field_data.py b/src/webflow/resources/products/types/product_sku_create_sku_field_data.py
deleted file mode 100644
index 621cba9..0000000
--- a/src/webflow/resources/products/types/product_sku_create_sku_field_data.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import datetime as dt
-import typing
-
-from ....core.datetime_utils import serialize_datetime
-from ....types.sku_value_list import SkuValueList
-from .product_sku_create_sku_field_data_compare_at_price import ProductSkuCreateSkuFieldDataCompareAtPrice
-from .product_sku_create_sku_field_data_ec_sku_billing_method import ProductSkuCreateSkuFieldDataEcSkuBillingMethod
-from .product_sku_create_sku_field_data_ec_sku_subscription_plan import (
- ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlan,
-)
-from .product_sku_create_sku_field_data_price import ProductSkuCreateSkuFieldDataPrice
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class ProductSkuCreateSkuFieldData(pydantic.BaseModel):
- """
- Standard and Custom fields for a SKU
- """
-
- sku_values: typing.Optional[SkuValueList] = pydantic.Field(alias="sku-values", default=None)
- name: str = pydantic.Field(description="Name of the Product")
- slug: str = pydantic.Field(description="URL structure of the Product in your site.")
- price: ProductSkuCreateSkuFieldDataPrice = pydantic.Field(description="price of SKU")
- compare_at_price: typing.Optional[ProductSkuCreateSkuFieldDataCompareAtPrice] = pydantic.Field(
- alias="compare-at-price", default=None, description="comparison price of SKU"
- )
- ec_sku_billing_method: typing.Optional[ProductSkuCreateSkuFieldDataEcSkuBillingMethod] = pydantic.Field(
- alias="ec-sku-billing-method", default=None, description="The billing method for your SKU"
- )
- ec_sku_subscription_plan: typing.Optional[ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlan] = pydantic.Field(
- alias="ec-sku-subscription-plan",
- default=None,
- description="If your billing method is a Subscription Plan, outline the type and frequency of the subscription.",
- )
- track_inventory: typing.Optional[bool] = pydantic.Field(
- alias="track-inventory",
- default=None,
- description="A boolean indicating whether inventory for this product should be tracked.",
- )
- quantity: typing.Optional[float] = pydantic.Field(
- default=None, description="Quantity of SKU that will be tracked as items are ordered."
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
diff --git a/src/webflow/resources/products/types/product_sku_create_sku_field_data_compare_at_price.py b/src/webflow/resources/products/types/product_sku_create_sku_field_data_compare_at_price.py
deleted file mode 100644
index ea8c8b8..0000000
--- a/src/webflow/resources/products/types/product_sku_create_sku_field_data_compare_at_price.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import datetime as dt
-import typing
-
-from ....core.datetime_utils import serialize_datetime
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class ProductSkuCreateSkuFieldDataCompareAtPrice(pydantic.BaseModel):
- """
- comparison price of SKU
- """
-
- value: typing.Optional[float] = pydantic.Field(default=None, description="Price of SKU")
- unit: typing.Optional[str] = pydantic.Field(default=None, description="Currency of Item")
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- json_encoders = {dt.datetime: serialize_datetime}
diff --git a/src/webflow/resources/products/types/product_sku_create_sku_field_data_ec_sku_billing_method.py b/src/webflow/resources/products/types/product_sku_create_sku_field_data_ec_sku_billing_method.py
deleted file mode 100644
index 9b4e545..0000000
--- a/src/webflow/resources/products/types/product_sku_create_sku_field_data_ec_sku_billing_method.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import enum
-import typing
-
-T_Result = typing.TypeVar("T_Result")
-
-
-class ProductSkuCreateSkuFieldDataEcSkuBillingMethod(str, enum.Enum):
- """
- The billing method for your SKU
- """
-
- ONE_TIME = "one-time"
- SUBSCRIPTION = "subscription"
-
- def visit(self, one_time: typing.Callable[[], T_Result], subscription: typing.Callable[[], T_Result]) -> T_Result:
- if self is ProductSkuCreateSkuFieldDataEcSkuBillingMethod.ONE_TIME:
- return one_time()
- if self is ProductSkuCreateSkuFieldDataEcSkuBillingMethod.SUBSCRIPTION:
- return subscription()
diff --git a/src/webflow/resources/products/types/product_sku_create_sku_field_data_ec_sku_subscription_plan.py b/src/webflow/resources/products/types/product_sku_create_sku_field_data_ec_sku_subscription_plan.py
deleted file mode 100644
index 16df5eb..0000000
--- a/src/webflow/resources/products/types/product_sku_create_sku_field_data_ec_sku_subscription_plan.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import datetime as dt
-import typing
-
-from ....core.datetime_utils import serialize_datetime
-from .product_sku_create_sku_field_data_ec_sku_subscription_plan_interval import (
- ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlanInterval,
-)
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlan(pydantic.BaseModel):
- """
- If your billing method is a Subscription Plan, outline the type and frequency of the subscription.
- """
-
- interval: typing.Optional[ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlanInterval] = pydantic.Field(
- default=None, description="Interval of subscription renewal"
- )
- frequency: typing.Optional[float] = pydantic.Field(default=None, description="Frequncy of billing within interval")
- trial: typing.Optional[float] = pydantic.Field(default=None, description="Number of days of a trial")
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- json_encoders = {dt.datetime: serialize_datetime}
diff --git a/src/webflow/resources/products/types/product_sku_create_sku_field_data_ec_sku_subscription_plan_interval.py b/src/webflow/resources/products/types/product_sku_create_sku_field_data_ec_sku_subscription_plan_interval.py
deleted file mode 100644
index 07093ba..0000000
--- a/src/webflow/resources/products/types/product_sku_create_sku_field_data_ec_sku_subscription_plan_interval.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import enum
-import typing
-
-T_Result = typing.TypeVar("T_Result")
-
-
-class ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlanInterval(str, enum.Enum):
- """
- Interval of subscription renewal
- """
-
- DAY = "day"
- WEEK = "week"
- MONTH = "month"
- YEAR = "year"
-
- def visit(
- self,
- day: typing.Callable[[], T_Result],
- week: typing.Callable[[], T_Result],
- month: typing.Callable[[], T_Result],
- year: typing.Callable[[], T_Result],
- ) -> T_Result:
- if self is ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlanInterval.DAY:
- return day()
- if self is ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlanInterval.WEEK:
- return week()
- if self is ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlanInterval.MONTH:
- return month()
- if self is ProductSkuCreateSkuFieldDataEcSkuSubscriptionPlanInterval.YEAR:
- return year()
diff --git a/src/webflow/resources/products/types/product_sku_create_sku_field_data_price.py b/src/webflow/resources/products/types/product_sku_create_sku_field_data_price.py
deleted file mode 100644
index 9a430e4..0000000
--- a/src/webflow/resources/products/types/product_sku_create_sku_field_data_price.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import datetime as dt
-import typing
-
-from ....core.datetime_utils import serialize_datetime
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class ProductSkuCreateSkuFieldDataPrice(pydantic.BaseModel):
- """
- price of SKU
- """
-
- required: typing.Optional[typing.Any] = None
- value: typing.Optional[float] = pydantic.Field(default=None, description="Price of SKU")
- unit: typing.Optional[str] = pydantic.Field(default=None, description="Currency of Item")
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- json_encoders = {dt.datetime: serialize_datetime}
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 c176596..a498e9f 100644
--- a/src/webflow/resources/products/types/products_create_sku_response.py
+++ b/src/webflow/resources/products/types/products_create_sku_response.py
@@ -1,29 +1,20 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ....core.datetime_utils import serialize_datetime
+import pydantic
+from ....core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from ....types.sku import Sku
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+class ProductsCreateSkuResponse(UniversalBaseModel):
+ skus: typing.List[Sku]
-class ProductsCreateSkuResponse(pydantic.BaseModel):
- skus: typing.Optional[typing.List[Sku]] = None
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/resources/scripts/__init__.py b/src/webflow/resources/scripts/__init__.py
index f3ea265..5cde020 100644
--- a/src/webflow/resources/scripts/__init__.py
+++ b/src/webflow/resources/scripts/__init__.py
@@ -1,2 +1,4 @@
# This file was auto-generated by Fern from our API Definition.
+# isort: skip_file
+
diff --git a/src/webflow/resources/scripts/client.py b/src/webflow/resources/scripts/client.py
index dae0212..f8a540e 100644
--- a/src/webflow/resources/scripts/client.py
+++ b/src/webflow/resources/scripts/client.py
@@ -1,26 +1,13 @@
# This file was auto-generated by Fern from our API Definition.
import typing
-import urllib.parse
-from json.decoder import JSONDecodeError
-from ...core.api_error import ApiError
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from ...core.jsonable_encoder import jsonable_encoder
-from ...core.remove_none_from_dict import remove_none_from_dict
from ...core.request_options import RequestOptions
-from ...errors.bad_request_error import BadRequestError
-from ...errors.internal_server_error import InternalServerError
-from ...errors.not_found_error import NotFoundError
-from ...errors.too_many_requests_error import TooManyRequestsError
-from ...errors.unauthorized_error import UnauthorizedError
-from ...types.custom_code_response import CustomCodeResponse
+from ...types.custom_code_hosted_response import CustomCodeHostedResponse
+from ...types.custom_code_inline_response import CustomCodeInlineResponse
from ...types.registered_script_list import RegisteredScriptList
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+from .raw_client import AsyncRawScriptsClient, RawScriptsClient
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
@@ -28,63 +15,55 @@
class ScriptsClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = RawScriptsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawScriptsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawScriptsClient
+ """
+ return self._raw_client
def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> RegisteredScriptList:
"""
- 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. Access to this endpoint requires a bearer token from a Data Client App. Required scope | `custom_code:read`
+ Get a list of scripts that have been registered to a site. A site can have a maximum of 800 registered scripts.
+
+
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Returns
+ -------
+ RegisteredScriptList
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.scripts.list(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/registered_scripts"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(RegisteredScriptList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.list(site_id, request_options=request_options)
+ return _response.data
def register_hosted(
self,
@@ -92,252 +71,209 @@ def register_hosted(
*,
hosted_location: str,
integrity_hash: str,
- can_copy: typing.Optional[bool] = OMIT,
version: str,
display_name: str,
+ can_copy: typing.Optional[bool] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> CustomCodeResponse:
+ ) -> 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. Access to this endpoint requires a bearer token from a Data Client App. Required scope | `custom_code:write`
+ 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`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- - hosted_location: str. URI for an externally hosted script location
+ hosted_location : str
+ URI for an externally hosted script location
- - integrity_hash: str. Sub-Resource Integrity Hash
+ integrity_hash : str
+ Sub-Resource Integrity Hash
- - can_copy: typing.Optional[bool]. Define whether the script can be copied on site duplication and transfer
+ version : str
+ A Semantic Version (SemVer) string, denoting the version of the script
- - version: str. A Semantic Version (SemVer) string, denoting the version of the script
+ display_name : str
+ User-facing name for the script. Must be between 1 and 50 alphanumeric characters
- - display_name: str. User-facing name for the script
+ can_copy : typing.Optional[bool]
+ Define whether the script can be copied on site duplication and transfer
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ CustomCodeHostedResponse
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.scripts.register_hosted(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
hosted_location="hostedLocation",
integrity_hash="integrityHash",
version="version",
display_name="displayName",
)
"""
- _request: typing.Dict[str, typing.Any] = {
- "hostedLocation": hosted_location,
- "integrityHash": integrity_hash,
- "version": version,
- "displayName": display_name,
- }
- if can_copy is not OMIT:
- _request["canCopy"] = can_copy
- _response = self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/registered_scripts/hosted",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.register_hosted(
+ site_id,
+ hosted_location=hosted_location,
+ integrity_hash=integrity_hash,
+ version=version,
+ display_name=display_name,
+ can_copy=can_copy,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(CustomCodeResponse, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
def register_inline(
self,
site_id: str,
*,
source_code: str,
- integrity_hash: typing.Optional[str] = OMIT,
- can_copy: typing.Optional[bool] = OMIT,
version: str,
display_name: str,
+ integrity_hash: typing.Optional[str] = OMIT,
+ can_copy: typing.Optional[bool] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> CustomCodeResponse:
+ ) -> 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. Access to this endpoint requires a bearer token from a Data Client App. Required scope | `custom_code:write`
+ Register an inline script to a site. Inline scripts are limited to 2000 characters.
+
+
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- Parameters:
- - site_id: str. Unique identifier for a Site
+ source_code : str
+ The code to be added to the site (to be hosted by Webflow).
- - source_code: str. The code to be added to the site (to be hosted by Webflow).
+ version : str
+ A Semantic Version (SemVer) string, denoting the version of the script
- - integrity_hash: typing.Optional[str]. Sub-Resource Integrity Hash. Only required for externally hosted scripts (passed via hostedLocation)
+ display_name : str
+ User-facing name for the script. Must be between 1 and 50 alphanumeric characters
- - can_copy: typing.Optional[bool]. Define whether the script can be copied on site duplication and transfer
+ integrity_hash : typing.Optional[str]
+ Sub-Resource Integrity Hash. Only required for externally hosted scripts (passed via hostedLocation)
- - version: str. A Semantic Version (SemVer) string, denoting the version of the script
+ can_copy : typing.Optional[bool]
+ Define whether the script can be copied on site duplication and transfer
- - display_name: str. User-facing name for the script
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Returns
+ -------
+ CustomCodeInlineResponse
+ Created
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.scripts.register_inline(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
source_code="alert('hello world');",
version="0.0.1",
display_name="Alert",
)
"""
- _request: typing.Dict[str, typing.Any] = {
- "sourceCode": source_code,
- "version": version,
- "displayName": display_name,
- }
- if integrity_hash is not OMIT:
- _request["integrityHash"] = integrity_hash
- if can_copy is not OMIT:
- _request["canCopy"] = can_copy
- _response = self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/registered_scripts/inline",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.register_inline(
+ site_id,
+ source_code=source_code,
+ version=version,
+ display_name=display_name,
+ integrity_hash=integrity_hash,
+ can_copy=can_copy,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(CustomCodeResponse, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
class AsyncScriptsClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = AsyncRawScriptsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawScriptsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawScriptsClient
+ """
+ return self._raw_client
async def list(
self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
) -> RegisteredScriptList:
"""
- 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. Access to this endpoint requires a bearer token from a Data Client App. Required scope | `custom_code:read`
+ Get a list of scripts that have been registered to a site. A site can have a maximum of 800 registered scripts.
+
+
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Returns
+ -------
+ RegisteredScriptList
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.scripts.list(
- site_id="site_id",
- )
+
+
+ async def main() -> None:
+ await client.scripts.list(
+ site_id="580e63e98c9a982ac9b8b741",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/registered_scripts"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(RegisteredScriptList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.list(site_id, request_options=request_options)
+ return _response.data
async def register_hosted(
self,
@@ -345,186 +281,159 @@ async def register_hosted(
*,
hosted_location: str,
integrity_hash: str,
- can_copy: typing.Optional[bool] = OMIT,
version: str,
display_name: str,
+ can_copy: typing.Optional[bool] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> CustomCodeResponse:
+ ) -> 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. Access to this endpoint requires a bearer token from a Data Client App. Required scope | `custom_code:write`
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ hosted_location : str
+ URI for an externally hosted script location
- Parameters:
- - site_id: str. Unique identifier for a Site
+ integrity_hash : str
+ Sub-Resource Integrity Hash
- - hosted_location: str. URI for an externally hosted script location
+ version : str
+ A Semantic Version (SemVer) string, denoting the version of the script
- - integrity_hash: str. Sub-Resource Integrity Hash
+ display_name : str
+ User-facing name for the script. Must be between 1 and 50 alphanumeric characters
- - can_copy: typing.Optional[bool]. Define whether the script can be copied on site duplication and transfer
+ can_copy : typing.Optional[bool]
+ Define whether the script can be copied on site duplication and transfer
- - version: str. A Semantic Version (SemVer) string, denoting the version of the script
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - display_name: str. User-facing name for the script
+ Returns
+ -------
+ CustomCodeHostedResponse
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.scripts.register_hosted(
- site_id="site_id",
- hosted_location="hostedLocation",
- integrity_hash="integrityHash",
- version="version",
- display_name="displayName",
- )
+
+
+ async def main() -> None:
+ await client.scripts.register_hosted(
+ site_id="580e63e98c9a982ac9b8b741",
+ hosted_location="hostedLocation",
+ integrity_hash="integrityHash",
+ version="version",
+ display_name="displayName",
+ )
+
+
+ asyncio.run(main())
"""
- _request: typing.Dict[str, typing.Any] = {
- "hostedLocation": hosted_location,
- "integrityHash": integrity_hash,
- "version": version,
- "displayName": display_name,
- }
- if can_copy is not OMIT:
- _request["canCopy"] = can_copy
- _response = await self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/registered_scripts/hosted",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.register_hosted(
+ site_id,
+ hosted_location=hosted_location,
+ integrity_hash=integrity_hash,
+ version=version,
+ display_name=display_name,
+ can_copy=can_copy,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(CustomCodeResponse, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
async def register_inline(
self,
site_id: str,
*,
source_code: str,
- integrity_hash: typing.Optional[str] = OMIT,
- can_copy: typing.Optional[bool] = OMIT,
version: str,
display_name: str,
+ integrity_hash: typing.Optional[str] = OMIT,
+ can_copy: typing.Optional[bool] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> CustomCodeResponse:
+ ) -> 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. Access to this endpoint requires a bearer token from a Data Client App. Required scope | `custom_code:write`
+ Register an inline script to a site. Inline scripts are limited to 2000 characters.
+
+
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ source_code : str
+ The code to be added to the site (to be hosted by Webflow).
- Parameters:
- - site_id: str. Unique identifier for a Site
+ version : str
+ A Semantic Version (SemVer) string, denoting the version of the script
- - source_code: str. The code to be added to the site (to be hosted by Webflow).
+ display_name : str
+ User-facing name for the script. Must be between 1 and 50 alphanumeric characters
- - integrity_hash: typing.Optional[str]. Sub-Resource Integrity Hash. Only required for externally hosted scripts (passed via hostedLocation)
+ integrity_hash : typing.Optional[str]
+ Sub-Resource Integrity Hash. Only required for externally hosted scripts (passed via hostedLocation)
- - can_copy: typing.Optional[bool]. Define whether the script can be copied on site duplication and transfer
+ can_copy : typing.Optional[bool]
+ Define whether the script can be copied on site duplication and transfer
- - version: str. A Semantic Version (SemVer) string, denoting the version of the script
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - display_name: str. User-facing name for the script
+ Returns
+ -------
+ CustomCodeInlineResponse
+ Created
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.scripts.register_inline(
- site_id="site_id",
- source_code="alert('hello world');",
- version="0.0.1",
- display_name="Alert",
- )
+
+
+ async def main() -> None:
+ await client.scripts.register_inline(
+ site_id="580e63e98c9a982ac9b8b741",
+ source_code="alert('hello world');",
+ version="0.0.1",
+ display_name="Alert",
+ )
+
+
+ asyncio.run(main())
"""
- _request: typing.Dict[str, typing.Any] = {
- "sourceCode": source_code,
- "version": version,
- "displayName": display_name,
- }
- if integrity_hash is not OMIT:
- _request["integrityHash"] = integrity_hash
- if can_copy is not OMIT:
- _request["canCopy"] = can_copy
- _response = await self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/registered_scripts/inline",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.register_inline(
+ site_id,
+ source_code=source_code,
+ version=version,
+ display_name=display_name,
+ integrity_hash=integrity_hash,
+ can_copy=can_copy,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(CustomCodeResponse, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
diff --git a/src/webflow/resources/scripts/raw_client.py b/src/webflow/resources/scripts/raw_client.py
new file mode 100644
index 0000000..0828f55
--- /dev/null
+++ b/src/webflow/resources/scripts/raw_client.py
@@ -0,0 +1,801 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from ...core.api_error import ApiError
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.http_response import AsyncHttpResponse, HttpResponse
+from ...core.jsonable_encoder import jsonable_encoder
+from ...core.parse_error import ParsingError
+from ...core.pydantic_utilities import parse_obj_as
+from ...core.request_options import RequestOptions
+from ...errors.bad_request_error import BadRequestError
+from ...errors.internal_server_error import InternalServerError
+from ...errors.not_found_error import NotFoundError
+from ...errors.too_many_requests_error import TooManyRequestsError
+from ...errors.unauthorized_error import UnauthorizedError
+from ...types.custom_code_hosted_response import CustomCodeHostedResponse
+from ...types.custom_code_inline_response import CustomCodeInlineResponse
+from ...types.error import Error
+from ...types.registered_script_list import RegisteredScriptList
+from pydantic import ValidationError
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RawScriptsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def list(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[RegisteredScriptList]:
+ """
+ Get a list of scripts that have been registered to a site. A site can have a maximum of 800 registered scripts.
+
+
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[RegisteredScriptList]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ RegisteredScriptList,
+ parse_obj_as(
+ type_=RegisteredScriptList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def register_hosted(
+ self,
+ site_id: str,
+ *,
+ hosted_location: str,
+ integrity_hash: str,
+ version: str,
+ display_name: str,
+ can_copy: typing.Optional[bool] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[CustomCodeHostedResponse]:
+ """
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ hosted_location : str
+ URI for an externally hosted script location
+
+ integrity_hash : str
+ Sub-Resource Integrity Hash
+
+ version : str
+ A Semantic Version (SemVer) string, denoting the version of the script
+
+ display_name : str
+ User-facing name for the script. Must be between 1 and 50 alphanumeric characters
+
+ can_copy : typing.Optional[bool]
+ Define whether the script can be copied on site duplication and transfer
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[CustomCodeHostedResponse]
+ Request was successful
+ """
+ _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,
+ "integrityHash": integrity_hash,
+ "canCopy": can_copy,
+ "version": version,
+ "displayName": display_name,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CustomCodeHostedResponse,
+ parse_obj_as(
+ type_=CustomCodeHostedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def register_inline(
+ self,
+ site_id: str,
+ *,
+ source_code: str,
+ version: str,
+ display_name: str,
+ integrity_hash: typing.Optional[str] = OMIT,
+ can_copy: typing.Optional[bool] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[CustomCodeInlineResponse]:
+ """
+ Register an inline script to a site. Inline scripts are limited to 2000 characters.
+
+
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ source_code : str
+ The code to be added to the site (to be hosted by Webflow).
+
+ version : str
+ A Semantic Version (SemVer) string, denoting the version of the script
+
+ display_name : str
+ User-facing name for the script. Must be between 1 and 50 alphanumeric characters
+
+ integrity_hash : typing.Optional[str]
+ Sub-Resource Integrity Hash. Only required for externally hosted scripts (passed via hostedLocation)
+
+ can_copy : typing.Optional[bool]
+ Define whether the script can be copied on site duplication and transfer
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[CustomCodeInlineResponse]
+ Created
+ """
+ _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,
+ "integrityHash": integrity_hash,
+ "canCopy": can_copy,
+ "version": version,
+ "displayName": display_name,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CustomCodeInlineResponse,
+ parse_obj_as(
+ type_=CustomCodeInlineResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawScriptsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def list(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[RegisteredScriptList]:
+ """
+ Get a list of scripts that have been registered to a site. A site can have a maximum of 800 registered scripts.
+
+
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[RegisteredScriptList]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ RegisteredScriptList,
+ parse_obj_as(
+ type_=RegisteredScriptList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def register_hosted(
+ self,
+ site_id: str,
+ *,
+ hosted_location: str,
+ integrity_hash: str,
+ version: str,
+ display_name: str,
+ can_copy: typing.Optional[bool] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[CustomCodeHostedResponse]:
+ """
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ hosted_location : str
+ URI for an externally hosted script location
+
+ integrity_hash : str
+ Sub-Resource Integrity Hash
+
+ version : str
+ A Semantic Version (SemVer) string, denoting the version of the script
+
+ display_name : str
+ User-facing name for the script. Must be between 1 and 50 alphanumeric characters
+
+ can_copy : typing.Optional[bool]
+ Define whether the script can be copied on site duplication and transfer
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[CustomCodeHostedResponse]
+ Request was successful
+ """
+ _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,
+ "integrityHash": integrity_hash,
+ "canCopy": can_copy,
+ "version": version,
+ "displayName": display_name,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CustomCodeHostedResponse,
+ parse_obj_as(
+ type_=CustomCodeHostedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def register_inline(
+ self,
+ site_id: str,
+ *,
+ source_code: str,
+ version: str,
+ display_name: str,
+ integrity_hash: typing.Optional[str] = OMIT,
+ can_copy: typing.Optional[bool] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[CustomCodeInlineResponse]:
+ """
+ Register an inline script to a site. Inline scripts are limited to 2000 characters.
+
+
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ source_code : str
+ The code to be added to the site (to be hosted by Webflow).
+
+ version : str
+ A Semantic Version (SemVer) string, denoting the version of the script
+
+ display_name : str
+ User-facing name for the script. Must be between 1 and 50 alphanumeric characters
+
+ integrity_hash : typing.Optional[str]
+ Sub-Resource Integrity Hash. Only required for externally hosted scripts (passed via hostedLocation)
+
+ can_copy : typing.Optional[bool]
+ Define whether the script can be copied on site duplication and transfer
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[CustomCodeInlineResponse]
+ Created
+ """
+ _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,
+ "integrityHash": integrity_hash,
+ "canCopy": can_copy,
+ "version": version,
+ "displayName": display_name,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ CustomCodeInlineResponse,
+ parse_obj_as(
+ type_=CustomCodeInlineResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/sites/__init__.py b/src/webflow/resources/sites/__init__.py
index c4ea3e7..fb81115 100644
--- a/src/webflow/resources/sites/__init__.py
+++ b/src/webflow/resources/sites/__init__.py
@@ -1,5 +1,85 @@
# This file was auto-generated by Fern from our API Definition.
-from .resources import activity_logs, scripts
+# isort: skip_file
-__all__ = ["activity_logs", "scripts"]
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .types import SitesPublishResponse
+ from .resources import (
+ CommentsGetCommentThreadRequestSortBy,
+ CommentsGetCommentThreadRequestSortOrder,
+ CommentsListCommentRepliesRequestSortBy,
+ CommentsListCommentRepliesRequestSortOrder,
+ CommentsListCommentThreadsRequestSortBy,
+ CommentsListCommentThreadsRequestSortOrder,
+ WellKnownFileContentType,
+ activity_logs,
+ comments,
+ forms,
+ plans,
+ redirects,
+ robots_txt,
+ scripts,
+ well_known,
+ )
+_dynamic_imports: typing.Dict[str, str] = {
+ "CommentsGetCommentThreadRequestSortBy": ".resources",
+ "CommentsGetCommentThreadRequestSortOrder": ".resources",
+ "CommentsListCommentRepliesRequestSortBy": ".resources",
+ "CommentsListCommentRepliesRequestSortOrder": ".resources",
+ "CommentsListCommentThreadsRequestSortBy": ".resources",
+ "CommentsListCommentThreadsRequestSortOrder": ".resources",
+ "SitesPublishResponse": ".types",
+ "WellKnownFileContentType": ".resources",
+ "activity_logs": ".resources",
+ "comments": ".resources",
+ "forms": ".resources",
+ "plans": ".resources",
+ "redirects": ".resources",
+ "robots_txt": ".resources",
+ "scripts": ".resources",
+ "well_known": ".resources",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = [
+ "CommentsGetCommentThreadRequestSortBy",
+ "CommentsGetCommentThreadRequestSortOrder",
+ "CommentsListCommentRepliesRequestSortBy",
+ "CommentsListCommentRepliesRequestSortOrder",
+ "CommentsListCommentThreadsRequestSortBy",
+ "CommentsListCommentThreadsRequestSortOrder",
+ "SitesPublishResponse",
+ "WellKnownFileContentType",
+ "activity_logs",
+ "comments",
+ "forms",
+ "plans",
+ "redirects",
+ "robots_txt",
+ "scripts",
+ "well_known",
+]
diff --git a/src/webflow/resources/sites/client.py b/src/webflow/resources/sites/client.py
index ee321fe..30b9ca2 100644
--- a/src/webflow/resources/sites/client.py
+++ b/src/webflow/resources/sites/client.py
@@ -1,199 +1,290 @@
# This file was auto-generated by Fern from our API Definition.
+from __future__ import annotations
+
import typing
-import urllib.parse
-from json.decoder import JSONDecodeError
-from ...core.api_error import ApiError
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from ...core.jsonable_encoder import jsonable_encoder
-from ...core.remove_none_from_dict import remove_none_from_dict
from ...core.request_options import RequestOptions
-from ...errors.bad_request_error import BadRequestError
-from ...errors.forbidden_error import ForbiddenError
-from ...errors.internal_server_error import InternalServerError
-from ...errors.not_found_error import NotFoundError
-from ...errors.too_many_requests_error import TooManyRequestsError
-from ...errors.unauthorized_error import UnauthorizedError
from ...types.domains import Domains
from ...types.site import Site
-from .resources.activity_logs.client import ActivityLogsClient, AsyncActivityLogsClient
-from .resources.scripts.client import AsyncScriptsClient, ScriptsClient
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
+from ...types.sites import Sites
+from .raw_client import AsyncRawSitesClient, RawSitesClient
+from .types.sites_publish_response import SitesPublishResponse
+
+if typing.TYPE_CHECKING:
+ from .resources.activity_logs.client import ActivityLogsClient, AsyncActivityLogsClient
+ from .resources.comments.client import AsyncCommentsClient, CommentsClient
+ from .resources.forms.client import AsyncFormsClient, FormsClient
+ from .resources.plans.client import AsyncPlansClient, PlansClient
+ from .resources.redirects.client import AsyncRedirectsClient, RedirectsClient
+ from .resources.robots_txt.client import AsyncRobotsTxtClient, RobotsTxtClient
+ from .resources.scripts.client import AsyncScriptsClient, ScriptsClient
+ from .resources.well_known.client import AsyncWellKnownClient, WellKnownClient
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
class SitesClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._raw_client = RawSitesClient(client_wrapper=client_wrapper)
self._client_wrapper = client_wrapper
- self.activity_logs = ActivityLogsClient(client_wrapper=self._client_wrapper)
- self.scripts = ScriptsClient(client_wrapper=self._client_wrapper)
+ self._redirects: typing.Optional[RedirectsClient] = None
+ self._plans: typing.Optional[PlansClient] = None
+ self._robots_txt: typing.Optional[RobotsTxtClient] = None
+ self._well_known: typing.Optional[WellKnownClient] = None
+ self._activity_logs: typing.Optional[ActivityLogsClient] = None
+ self._comments: typing.Optional[CommentsClient] = None
+ self._scripts: typing.Optional[ScriptsClient] = None
+ self._forms: typing.Optional[FormsClient] = None
+
+ @property
+ def with_raw_response(self) -> RawSitesClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
- def list(self, *, request_options: typing.Optional[RequestOptions] = None) -> Site:
+ Returns
+ -------
+ RawSitesClient
+ """
+ return self._raw_client
+
+ def create(
+ self,
+ workspace_id: str,
+ *,
+ name: str,
+ template_name: typing.Optional[str] = OMIT,
+ parent_folder_id: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> Site:
"""
- List of all sites the provided access token is able to access. Required scope | `sites:read`
+ Create a site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope | `workspace:write`
+
+ Parameters
+ ----------
+ workspace_id : str
+ Unique identifier for a Workspace
+
+ name : str
+ The name of the site
+
+ template_name : typing.Optional[str]
+ The workspace or marketplace template to use
- Parameters:
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ parent_folder_id : typing.Optional[str]
+ MegaDodo Publications - Potential Book Ideas
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Site
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
- client.sites.list()
+ client.sites.create(
+ workspace_id="580e63e98c9a982ac9b8b741",
+ name="The Hitchhiker's Guide to the Galaxy",
+ )
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "sites"),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.create(
+ workspace_id,
+ name=name,
+ template_name=template_name,
+ parent_folder_id=parent_folder_id,
+ request_options=request_options,
+ )
+ return _response.data
+
+ def list(self, *, request_options: typing.Optional[RequestOptions] = None) -> Sites:
+ """
+ List of all sites the provided access token is able to access.
+
+ Required scope | `sites:read`
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Sites
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Site, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ client.sites.list()
+ """
+ _response = self._raw_client.list(request_options=request_options)
+ return _response.data
def get(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Site:
"""
- Get a site by site id Required scope | `sites:read`
+ Get details of a site.
+
+ Required scope | `sites:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Returns
+ -------
+ Site
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.sites.get(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
+ )
+ """
+ _response = self._raw_client.get(site_id, request_options=request_options)
+ return _response.data
+
+ def delete(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
+ """
+ Delete a site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope | `sites:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ from webflow import Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.sites.delete(
+ site_id="580e63e98c9a982ac9b8b741",
+ )
+ """
+ _response = self._raw_client.delete(site_id, request_options=request_options)
+ return _response.data
+
+ def update(
+ self,
+ site_id: str,
+ *,
+ name: typing.Optional[str] = OMIT,
+ parent_folder_id: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> Site:
+ """
+ Update a site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope | `sites:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ name : typing.Optional[str]
+ The name of the site
+
+ parent_folder_id : typing.Optional[str]
+ The parent folder ID of the site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Site
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.sites.update(
+ site_id="580e63e98c9a982ac9b8b741",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}"),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.update(
+ site_id, name=name, parent_folder_id=parent_folder_id, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Site, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
def get_custom_domain(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Domains:
"""
- Get a list of all custom domains related to site. Required scope | `sites:read`
+ Get a list of all custom domains related to site.
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Required scope | `sites:read`
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Domains
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.sites.get_custom_domain(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/custom_domains"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Domains, _response.json()) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.get_custom_domain(site_id, request_options=request_options)
+ return _response.data
def publish(
self,
@@ -202,246 +293,431 @@ def publish(
custom_domains: typing.Optional[typing.Sequence[str]] = OMIT,
publish_to_webflow_subdomain: typing.Optional[bool] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> None:
+ ) -> SitesPublishResponse:
"""
- Publish a site to one more more domains. Required scope | `sites:write`
+ 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 specific rate limit of one successful publish queue per minute.
+
+ Required scope | `sites:write`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- - custom_domains: typing.Optional[typing.Sequence[str]]. Array of Custom Domain ids to publish
+ custom_domains : typing.Optional[typing.Sequence[str]]
+ Array of Custom Domain IDs to publish
- - publish_to_webflow_subdomain: typing.Optional[bool]. Choice of whether to publish to the default Webflow Subdomain
+ publish_to_webflow_subdomain : typing.Optional[bool]
+ Choice of whether to publish to the default Webflow Subdomain
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ SitesPublishResponse
+ Request accepted
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.sites.publish(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
+ custom_domains=["660c6449dd97ebc7346ac629", "660c6449dd97ebc7346ac62f"],
publish_to_webflow_subdomain=False,
)
"""
- _request: typing.Dict[str, typing.Any] = {}
- if custom_domains is not OMIT:
- _request["customDomains"] = custom_domains
- if publish_to_webflow_subdomain is not OMIT:
- _request["publishToWebflowSubdomain"] = publish_to_webflow_subdomain
- _response = self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/publish"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.publish(
+ site_id,
+ custom_domains=custom_domains,
+ publish_to_webflow_subdomain=publish_to_webflow_subdomain,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
+
+ @property
+ def redirects(self):
+ if self._redirects is None:
+ from .resources.redirects.client import RedirectsClient # noqa: E402
+
+ self._redirects = RedirectsClient(client_wrapper=self._client_wrapper)
+ return self._redirects
+
+ @property
+ def plans(self):
+ if self._plans is None:
+ from .resources.plans.client import PlansClient # noqa: E402
+
+ self._plans = PlansClient(client_wrapper=self._client_wrapper)
+ return self._plans
+
+ @property
+ def robots_txt(self):
+ if self._robots_txt is None:
+ from .resources.robots_txt.client import RobotsTxtClient # noqa: E402
+
+ self._robots_txt = RobotsTxtClient(client_wrapper=self._client_wrapper)
+ return self._robots_txt
+
+ @property
+ def well_known(self):
+ if self._well_known is None:
+ from .resources.well_known.client import WellKnownClient # noqa: E402
+
+ self._well_known = WellKnownClient(client_wrapper=self._client_wrapper)
+ return self._well_known
+
+ @property
+ def activity_logs(self):
+ if self._activity_logs is None:
+ from .resources.activity_logs.client import ActivityLogsClient # noqa: E402
+
+ self._activity_logs = ActivityLogsClient(client_wrapper=self._client_wrapper)
+ return self._activity_logs
+
+ @property
+ def comments(self):
+ if self._comments is None:
+ from .resources.comments.client import CommentsClient # noqa: E402
+
+ self._comments = CommentsClient(client_wrapper=self._client_wrapper)
+ return self._comments
+
+ @property
+ def scripts(self):
+ if self._scripts is None:
+ from .resources.scripts.client import ScriptsClient # noqa: E402
+
+ self._scripts = ScriptsClient(client_wrapper=self._client_wrapper)
+ return self._scripts
+
+ @property
+ def forms(self):
+ if self._forms is None:
+ from .resources.forms.client import FormsClient # noqa: E402
+
+ self._forms = FormsClient(client_wrapper=self._client_wrapper)
+ return self._forms
class AsyncSitesClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._raw_client = AsyncRawSitesClient(client_wrapper=client_wrapper)
self._client_wrapper = client_wrapper
- self.activity_logs = AsyncActivityLogsClient(client_wrapper=self._client_wrapper)
- self.scripts = AsyncScriptsClient(client_wrapper=self._client_wrapper)
+ self._redirects: typing.Optional[AsyncRedirectsClient] = None
+ self._plans: typing.Optional[AsyncPlansClient] = None
+ self._robots_txt: typing.Optional[AsyncRobotsTxtClient] = None
+ self._well_known: typing.Optional[AsyncWellKnownClient] = None
+ self._activity_logs: typing.Optional[AsyncActivityLogsClient] = None
+ self._comments: typing.Optional[AsyncCommentsClient] = None
+ self._scripts: typing.Optional[AsyncScriptsClient] = None
+ self._forms: typing.Optional[AsyncFormsClient] = None
+
+ @property
+ def with_raw_response(self) -> AsyncRawSitesClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
- async def list(self, *, request_options: typing.Optional[RequestOptions] = None) -> Site:
+ Returns
+ -------
+ AsyncRawSitesClient
"""
- List of all sites the provided access token is able to access. Required scope | `sites:read`
+ return self._raw_client
+
+ async def create(
+ self,
+ workspace_id: str,
+ *,
+ name: str,
+ template_name: typing.Optional[str] = OMIT,
+ parent_folder_id: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> Site:
+ """
+ Create a site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope | `workspace:write`
+
+ Parameters
+ ----------
+ workspace_id : str
+ Unique identifier for a Workspace
+
+ name : str
+ The name of the site
+
+ template_name : typing.Optional[str]
+ The workspace or marketplace template to use
+
+ parent_folder_id : typing.Optional[str]
+ MegaDodo Publications - Potential Book Ideas
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Site
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
- Parameters:
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.sites.list()
- """
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "sites"),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+
+
+ async def main() -> None:
+ await client.sites.create(
+ workspace_id="580e63e98c9a982ac9b8b741",
+ name="The Hitchhiker's Guide to the Galaxy",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.create(
+ workspace_id,
+ name=name,
+ template_name=template_name,
+ parent_folder_id=parent_folder_id,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Site, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
+
+ async def list(self, *, request_options: typing.Optional[RequestOptions] = None) -> Sites:
+ """
+ List of all sites the provided access token is able to access.
+
+ Required scope | `sites:read`
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Sites
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.sites.list()
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.list(request_options=request_options)
+ return _response.data
async def get(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Site:
"""
- Get a site by site id Required scope | `sites:read`
+ Get details of a site.
+
+ Required scope | `sites:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Site
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.sites.get(
+ site_id="580e63e98c9a982ac9b8b741",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.get(site_id, request_options=request_options)
+ return _response.data
+
+ async def delete(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
+ """
+ Delete a site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope | `sites:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- Parameters:
- - site_id: str. Unique identifier for a Site
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.sites.get(
- site_id="site_id",
+
+
+ async def main() -> None:
+ await client.sites.delete(
+ site_id="580e63e98c9a982ac9b8b741",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.delete(site_id, request_options=request_options)
+ return _response.data
+
+ async def update(
+ self,
+ site_id: str,
+ *,
+ name: typing.Optional[str] = OMIT,
+ parent_folder_id: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> Site:
+ """
+ Update a site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope | `sites:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ name : typing.Optional[str]
+ The name of the site
+
+ parent_folder_id : typing.Optional[str]
+ The parent folder ID of the site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Site
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
)
+
+
+ async def main() -> None:
+ await client.sites.update(
+ site_id="580e63e98c9a982ac9b8b741",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}"),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.update(
+ site_id, name=name, parent_folder_id=parent_folder_id, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Site, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
async def get_custom_domain(
self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
) -> Domains:
"""
- Get a list of all custom domains related to site. Required scope | `sites:read`
+ Get a list of all custom domains related to site.
+
+ Required scope | `sites:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- Parameters:
- - site_id: str. Unique identifier for a Site
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Returns
+ -------
+ Domains
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.sites.get_custom_domain(
- site_id="site_id",
- )
+
+
+ async def main() -> None:
+ await client.sites.get_custom_domain(
+ site_id="580e63e98c9a982ac9b8b741",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/custom_domains"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Domains, _response.json()) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.get_custom_domain(site_id, request_options=request_options)
+ return _response.data
async def publish(
self,
@@ -450,74 +726,124 @@ async def publish(
custom_domains: typing.Optional[typing.Sequence[str]] = OMIT,
publish_to_webflow_subdomain: typing.Optional[bool] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> None:
+ ) -> SitesPublishResponse:
"""
- Publish a site to one more more domains. Required scope | `sites:write`
+ 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.
- Parameters:
- - site_id: str. Unique identifier for a Site
+ This endpoint has a specific rate limit of one successful publish queue per minute.
- - custom_domains: typing.Optional[typing.Sequence[str]]. Array of Custom Domain ids to publish
+ Required scope | `sites:write`
- - publish_to_webflow_subdomain: typing.Optional[bool]. Choice of whether to publish to the default Webflow Subdomain
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ custom_domains : typing.Optional[typing.Sequence[str]]
+ Array of Custom Domain IDs to publish
+
+ publish_to_webflow_subdomain : typing.Optional[bool]
+ Choice of whether to publish to the default Webflow Subdomain
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ SitesPublishResponse
+ Request accepted
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.sites.publish(
- site_id="site_id",
- publish_to_webflow_subdomain=False,
- )
+
+
+ async def main() -> None:
+ await client.sites.publish(
+ site_id="580e63e98c9a982ac9b8b741",
+ custom_domains=["660c6449dd97ebc7346ac629", "660c6449dd97ebc7346ac62f"],
+ publish_to_webflow_subdomain=False,
+ )
+
+
+ asyncio.run(main())
"""
- _request: typing.Dict[str, typing.Any] = {}
- if custom_domains is not OMIT:
- _request["customDomains"] = custom_domains
- if publish_to_webflow_subdomain is not OMIT:
- _request["publishToWebflowSubdomain"] = publish_to_webflow_subdomain
- _response = await self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/publish"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.publish(
+ site_id,
+ custom_domains=custom_domains,
+ publish_to_webflow_subdomain=publish_to_webflow_subdomain,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
+
+ @property
+ def redirects(self):
+ if self._redirects is None:
+ from .resources.redirects.client import AsyncRedirectsClient # noqa: E402
+
+ self._redirects = AsyncRedirectsClient(client_wrapper=self._client_wrapper)
+ return self._redirects
+
+ @property
+ def plans(self):
+ if self._plans is None:
+ from .resources.plans.client import AsyncPlansClient # noqa: E402
+
+ self._plans = AsyncPlansClient(client_wrapper=self._client_wrapper)
+ return self._plans
+
+ @property
+ def robots_txt(self):
+ if self._robots_txt is None:
+ from .resources.robots_txt.client import AsyncRobotsTxtClient # noqa: E402
+
+ self._robots_txt = AsyncRobotsTxtClient(client_wrapper=self._client_wrapper)
+ return self._robots_txt
+
+ @property
+ def well_known(self):
+ if self._well_known is None:
+ from .resources.well_known.client import AsyncWellKnownClient # noqa: E402
+
+ self._well_known = AsyncWellKnownClient(client_wrapper=self._client_wrapper)
+ return self._well_known
+
+ @property
+ def activity_logs(self):
+ if self._activity_logs is None:
+ from .resources.activity_logs.client import AsyncActivityLogsClient # noqa: E402
+
+ self._activity_logs = AsyncActivityLogsClient(client_wrapper=self._client_wrapper)
+ return self._activity_logs
+
+ @property
+ def comments(self):
+ if self._comments is None:
+ from .resources.comments.client import AsyncCommentsClient # noqa: E402
+
+ self._comments = AsyncCommentsClient(client_wrapper=self._client_wrapper)
+ return self._comments
+
+ @property
+ def scripts(self):
+ if self._scripts is None:
+ from .resources.scripts.client import AsyncScriptsClient # noqa: E402
+
+ self._scripts = AsyncScriptsClient(client_wrapper=self._client_wrapper)
+ return self._scripts
+
+ @property
+ def forms(self):
+ if self._forms is None:
+ from .resources.forms.client import AsyncFormsClient # noqa: E402
+
+ self._forms = AsyncFormsClient(client_wrapper=self._client_wrapper)
+ return self._forms
diff --git a/src/webflow/resources/sites/raw_client.py b/src/webflow/resources/sites/raw_client.py
new file mode 100644
index 0000000..cc08250
--- /dev/null
+++ b/src/webflow/resources/sites/raw_client.py
@@ -0,0 +1,1587 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from ...core.api_error import ApiError
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.http_response import AsyncHttpResponse, HttpResponse
+from ...core.jsonable_encoder import jsonable_encoder
+from ...core.parse_error import ParsingError
+from ...core.pydantic_utilities import parse_obj_as
+from ...core.request_options import RequestOptions
+from ...errors.bad_request_error import BadRequestError
+from ...errors.forbidden_error import ForbiddenError
+from ...errors.internal_server_error import InternalServerError
+from ...errors.not_found_error import NotFoundError
+from ...errors.too_many_requests_error import TooManyRequestsError
+from ...errors.unauthorized_error import UnauthorizedError
+from ...types.domains import Domains
+from ...types.error import Error
+from ...types.site import Site
+from ...types.sites import Sites
+from .types.sites_publish_response import SitesPublishResponse
+from pydantic import ValidationError
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RawSitesClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def create(
+ self,
+ workspace_id: str,
+ *,
+ name: str,
+ template_name: typing.Optional[str] = OMIT,
+ parent_folder_id: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[Site]:
+ """
+ Create a site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope | `workspace:write`
+
+ Parameters
+ ----------
+ workspace_id : str
+ Unique identifier for a Workspace
+
+ name : str
+ The name of the site
+
+ template_name : typing.Optional[str]
+ The workspace or marketplace template to use
+
+ parent_folder_id : typing.Optional[str]
+ MegaDodo Publications - Potential Book Ideas
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Site]
+ Request was successful
+ """
+ _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,
+ "templateName": template_name,
+ "parentFolderId": parent_folder_id,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Site,
+ parse_obj_as(
+ type_=Site, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def list(self, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[Sites]:
+ """
+ List of all sites the provided access token is able to access.
+
+ Required scope | `sites:read`
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Sites]
+ Request was successful
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ "sites",
+ base_url=self._client_wrapper.get_environment().base,
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Sites,
+ parse_obj_as(
+ type_=Sites, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def get(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[Site]:
+ """
+ Get details of a site.
+
+ Required scope | `sites:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Site]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Site,
+ parse_obj_as(
+ type_=Site, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def delete(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[None]:
+ """
+ Delete a site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope | `sites:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[None]
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"sites/{jsonable_encoder(site_id)}",
+ base_url=self._client_wrapper.get_environment().base,
+ method="DELETE",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return HttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def update(
+ self,
+ site_id: str,
+ *,
+ name: typing.Optional[str] = OMIT,
+ parent_folder_id: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[Site]:
+ """
+ Update a site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope | `sites:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ name : typing.Optional[str]
+ The name of the site
+
+ parent_folder_id : typing.Optional[str]
+ The parent folder ID of the site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Site]
+ Request was successful
+ """
+ _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,
+ "parentFolderId": parent_folder_id,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Site,
+ parse_obj_as(
+ type_=Site, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def get_custom_domain(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[Domains]:
+ """
+ Get a list of all custom domains related to site.
+
+ Required scope | `sites:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Domains]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Domains,
+ parse_obj_as(
+ type_=Domains, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def publish(
+ self,
+ site_id: str,
+ *,
+ custom_domains: typing.Optional[typing.Sequence[str]] = OMIT,
+ publish_to_webflow_subdomain: typing.Optional[bool] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[SitesPublishResponse]:
+ """
+ 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 specific rate limit of one successful publish queue per minute.
+
+ Required scope | `sites:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ custom_domains : typing.Optional[typing.Sequence[str]]
+ Array of Custom Domain IDs to publish
+
+ publish_to_webflow_subdomain : typing.Optional[bool]
+ Choice of whether to publish to the default Webflow Subdomain
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[SitesPublishResponse]
+ Request accepted
+ """
+ _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,
+ "publishToWebflowSubdomain": publish_to_webflow_subdomain,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ SitesPublishResponse,
+ parse_obj_as(
+ type_=SitesPublishResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawSitesClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def create(
+ self,
+ workspace_id: str,
+ *,
+ name: str,
+ template_name: typing.Optional[str] = OMIT,
+ parent_folder_id: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[Site]:
+ """
+ Create a site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope | `workspace:write`
+
+ Parameters
+ ----------
+ workspace_id : str
+ Unique identifier for a Workspace
+
+ name : str
+ The name of the site
+
+ template_name : typing.Optional[str]
+ The workspace or marketplace template to use
+
+ parent_folder_id : typing.Optional[str]
+ MegaDodo Publications - Potential Book Ideas
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Site]
+ Request was successful
+ """
+ _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,
+ "templateName": template_name,
+ "parentFolderId": parent_folder_id,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Site,
+ parse_obj_as(
+ type_=Site, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def list(self, *, request_options: typing.Optional[RequestOptions] = None) -> AsyncHttpResponse[Sites]:
+ """
+ List of all sites the provided access token is able to access.
+
+ Required scope | `sites:read`
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Sites]
+ Request was successful
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ "sites",
+ base_url=self._client_wrapper.get_environment().base,
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Sites,
+ parse_obj_as(
+ type_=Sites, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def get(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[Site]:
+ """
+ Get details of a site.
+
+ Required scope | `sites:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Site]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Site,
+ parse_obj_as(
+ type_=Site, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def delete(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[None]:
+ """
+ Delete a site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope | `sites:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[None]
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"sites/{jsonable_encoder(site_id)}",
+ base_url=self._client_wrapper.get_environment().base,
+ method="DELETE",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return AsyncHttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def update(
+ self,
+ site_id: str,
+ *,
+ name: typing.Optional[str] = OMIT,
+ parent_folder_id: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[Site]:
+ """
+ Update a site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope | `sites:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ name : typing.Optional[str]
+ The name of the site
+
+ parent_folder_id : typing.Optional[str]
+ The parent folder ID of the site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Site]
+ Request was successful
+ """
+ _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,
+ "parentFolderId": parent_folder_id,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Site,
+ parse_obj_as(
+ type_=Site, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def get_custom_domain(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[Domains]:
+ """
+ Get a list of all custom domains related to site.
+
+ Required scope | `sites:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Domains]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Domains,
+ parse_obj_as(
+ type_=Domains, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def publish(
+ self,
+ site_id: str,
+ *,
+ custom_domains: typing.Optional[typing.Sequence[str]] = OMIT,
+ publish_to_webflow_subdomain: typing.Optional[bool] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[SitesPublishResponse]:
+ """
+ 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 specific rate limit of one successful publish queue per minute.
+
+ Required scope | `sites:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ custom_domains : typing.Optional[typing.Sequence[str]]
+ Array of Custom Domain IDs to publish
+
+ publish_to_webflow_subdomain : typing.Optional[bool]
+ Choice of whether to publish to the default Webflow Subdomain
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[SitesPublishResponse]
+ Request accepted
+ """
+ _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,
+ "publishToWebflowSubdomain": publish_to_webflow_subdomain,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ SitesPublishResponse,
+ parse_obj_as(
+ type_=SitesPublishResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/sites/resources/__init__.py b/src/webflow/resources/sites/resources/__init__.py
index b143a1f..529b1de 100644
--- a/src/webflow/resources/sites/resources/__init__.py
+++ b/src/webflow/resources/sites/resources/__init__.py
@@ -1,5 +1,75 @@
# This file was auto-generated by Fern from our API Definition.
-from . import activity_logs, scripts
+# isort: skip_file
-__all__ = ["activity_logs", "scripts"]
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from . import activity_logs, comments, forms, plans, redirects, robots_txt, scripts, well_known
+ from .comments import (
+ CommentsGetCommentThreadRequestSortBy,
+ CommentsGetCommentThreadRequestSortOrder,
+ CommentsListCommentRepliesRequestSortBy,
+ CommentsListCommentRepliesRequestSortOrder,
+ CommentsListCommentThreadsRequestSortBy,
+ CommentsListCommentThreadsRequestSortOrder,
+ )
+ from .well_known import WellKnownFileContentType
+_dynamic_imports: typing.Dict[str, str] = {
+ "CommentsGetCommentThreadRequestSortBy": ".comments",
+ "CommentsGetCommentThreadRequestSortOrder": ".comments",
+ "CommentsListCommentRepliesRequestSortBy": ".comments",
+ "CommentsListCommentRepliesRequestSortOrder": ".comments",
+ "CommentsListCommentThreadsRequestSortBy": ".comments",
+ "CommentsListCommentThreadsRequestSortOrder": ".comments",
+ "WellKnownFileContentType": ".well_known",
+ "activity_logs": ".activity_logs",
+ "comments": ".comments",
+ "forms": ".forms",
+ "plans": ".plans",
+ "redirects": ".redirects",
+ "robots_txt": ".robots_txt",
+ "scripts": ".scripts",
+ "well_known": ".well_known",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = [
+ "CommentsGetCommentThreadRequestSortBy",
+ "CommentsGetCommentThreadRequestSortOrder",
+ "CommentsListCommentRepliesRequestSortBy",
+ "CommentsListCommentRepliesRequestSortOrder",
+ "CommentsListCommentThreadsRequestSortBy",
+ "CommentsListCommentThreadsRequestSortOrder",
+ "WellKnownFileContentType",
+ "activity_logs",
+ "comments",
+ "forms",
+ "plans",
+ "redirects",
+ "robots_txt",
+ "scripts",
+ "well_known",
+]
diff --git a/src/webflow/resources/sites/resources/activity_logs/__init__.py b/src/webflow/resources/sites/resources/activity_logs/__init__.py
index f3ea265..5cde020 100644
--- a/src/webflow/resources/sites/resources/activity_logs/__init__.py
+++ b/src/webflow/resources/sites/resources/activity_logs/__init__.py
@@ -1,2 +1,4 @@
# This file was auto-generated by Fern from our API Definition.
+# isort: skip_file
+
diff --git a/src/webflow/resources/sites/resources/activity_logs/client.py b/src/webflow/resources/sites/resources/activity_logs/client.py
index a0edffd..1e999f7 100644
--- a/src/webflow/resources/sites/resources/activity_logs/client.py
+++ b/src/webflow/resources/sites/resources/activity_logs/client.py
@@ -1,181 +1,148 @@
# This file was auto-generated by Fern from our API Definition.
import typing
-import urllib.parse
-from json.decoder import JSONDecodeError
-from .....core.api_error import ApiError
from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from .....core.jsonable_encoder import jsonable_encoder
-from .....core.remove_none_from_dict import remove_none_from_dict
from .....core.request_options import RequestOptions
-from .....errors.forbidden_error import ForbiddenError
-from .....errors.internal_server_error import InternalServerError
-from .....errors.not_found_error import NotFoundError
-from .....errors.too_many_requests_error import TooManyRequestsError
from .....types.site_activity_log_response import SiteActivityLogResponse
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+from .raw_client import AsyncRawActivityLogsClient, RawActivityLogsClient
class ActivityLogsClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = RawActivityLogsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawActivityLogsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawActivityLogsClient
+ """
+ return self._raw_client
def list(
self,
site_id: str,
*,
- limit: typing.Optional[float] = None,
- offset: typing.Optional[float] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
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:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- - limit: typing.Optional[float]. Maximum number of records to be returned (max limit: 100)
+ limit : typing.Optional[int]
+ 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
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ SiteActivityLogResponse
+ A list of site activity logs
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.sites.activity_logs.list(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
+ limit=1,
+ offset=1,
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/activity_logs"
- ),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "limit": limit,
- "offset": offset,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(SiteActivityLogResponse, _response.json()) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.list(site_id, limit=limit, offset=offset, request_options=request_options)
+ return _response.data
class AsyncActivityLogsClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = AsyncRawActivityLogsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawActivityLogsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawActivityLogsClient
+ """
+ return self._raw_client
async def list(
self,
site_id: str,
*,
- limit: typing.Optional[float] = None,
- offset: typing.Optional[float] = None,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
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
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
- Parameters:
- - site_id: str. Unique identifier for a Site
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - limit: typing.Optional[float]. Maximum number of records to be returned (max limit: 100)
+ Returns
+ -------
+ SiteActivityLogResponse
+ A list of site activity logs
- - offset: typing.Optional[float]. Offset used for pagination if the results have more than limit records
+ Examples
+ --------
+ import asyncio
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.sites.activity_logs.list(
- site_id="site_id",
- )
+
+
+ async def main() -> None:
+ await client.sites.activity_logs.list(
+ site_id="580e63e98c9a982ac9b8b741",
+ limit=1,
+ offset=1,
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/activity_logs"
- ),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "limit": limit,
- "offset": offset,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(SiteActivityLogResponse, _response.json()) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.list(site_id, limit=limit, offset=offset, request_options=request_options)
+ return _response.data
diff --git a/src/webflow/resources/sites/resources/activity_logs/raw_client.py b/src/webflow/resources/sites/resources/activity_logs/raw_client.py
new file mode 100644
index 0000000..4c6453a
--- /dev/null
+++ b/src/webflow/resources/sites/resources/activity_logs/raw_client.py
@@ -0,0 +1,243 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from .....core.api_error import ApiError
+from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .....core.http_response import AsyncHttpResponse, HttpResponse
+from .....core.jsonable_encoder import jsonable_encoder
+from .....core.parse_error import ParsingError
+from .....core.pydantic_utilities import parse_obj_as
+from .....core.request_options import RequestOptions
+from .....errors.forbidden_error import ForbiddenError
+from .....errors.internal_server_error import InternalServerError
+from .....errors.not_found_error import NotFoundError
+from .....errors.too_many_requests_error import TooManyRequestsError
+from .....types.error import Error
+from .....types.site_activity_log_response import SiteActivityLogResponse
+from pydantic import ValidationError
+
+
+class RawActivityLogsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def list(
+ self,
+ site_id: str,
+ *,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[SiteActivityLogResponse]:
+ """
+ Retrieve Activity Logs for a specific Site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope: `site_activity:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[SiteActivityLogResponse]
+ A list of site activity logs
+ """
+ _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,
+ "offset": offset,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ SiteActivityLogResponse,
+ parse_obj_as(
+ type_=SiteActivityLogResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawActivityLogsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def list(
+ self,
+ site_id: str,
+ *,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[SiteActivityLogResponse]:
+ """
+ Retrieve Activity Logs for a specific Site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope: `site_activity:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[SiteActivityLogResponse]
+ A list of site activity logs
+ """
+ _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,
+ "offset": offset,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ SiteActivityLogResponse,
+ parse_obj_as(
+ type_=SiteActivityLogResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/sites/resources/comments/__init__.py b/src/webflow/resources/sites/resources/comments/__init__.py
new file mode 100644
index 0000000..91af2b0
--- /dev/null
+++ b/src/webflow/resources/sites/resources/comments/__init__.py
@@ -0,0 +1,55 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .types import (
+ CommentsGetCommentThreadRequestSortBy,
+ CommentsGetCommentThreadRequestSortOrder,
+ CommentsListCommentRepliesRequestSortBy,
+ CommentsListCommentRepliesRequestSortOrder,
+ CommentsListCommentThreadsRequestSortBy,
+ CommentsListCommentThreadsRequestSortOrder,
+ )
+_dynamic_imports: typing.Dict[str, str] = {
+ "CommentsGetCommentThreadRequestSortBy": ".types",
+ "CommentsGetCommentThreadRequestSortOrder": ".types",
+ "CommentsListCommentRepliesRequestSortBy": ".types",
+ "CommentsListCommentRepliesRequestSortOrder": ".types",
+ "CommentsListCommentThreadsRequestSortBy": ".types",
+ "CommentsListCommentThreadsRequestSortOrder": ".types",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = [
+ "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..8fbae1e
--- /dev/null
+++ b/src/webflow/resources/sites/resources/comments/client.py
@@ -0,0 +1,558 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .....core.request_options import RequestOptions
+from .....types.comment_reply_list import CommentReplyList
+from .....types.comment_thread import CommentThread
+from .....types.comment_thread_list import CommentThreadList
+from .raw_client import AsyncRawCommentsClient, RawCommentsClient
+from .types.comments_get_comment_thread_request_sort_by import CommentsGetCommentThreadRequestSortBy
+from .types.comments_get_comment_thread_request_sort_order import CommentsGetCommentThreadRequestSortOrder
+from .types.comments_list_comment_replies_request_sort_by import CommentsListCommentRepliesRequestSortBy
+from .types.comments_list_comment_replies_request_sort_order import CommentsListCommentRepliesRequestSortOrder
+from .types.comments_list_comment_threads_request_sort_by import CommentsListCommentThreadsRequestSortBy
+from .types.comments_list_comment_threads_request_sort_order import CommentsListCommentThreadsRequestSortOrder
+
+
+class CommentsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._raw_client = RawCommentsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawCommentsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawCommentsClient
+ """
+ return self._raw_client
+
+ def list_comment_threads(
+ self,
+ site_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = 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.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ 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",
+ offset=1,
+ limit=1,
+ sort_by="createdOn",
+ sort_order="asc",
+ )
+ """
+ _response = self._raw_client.list_comment_threads(
+ site_id,
+ locale_id=locale_id,
+ offset=offset,
+ limit=limit,
+ sort_by=sort_by,
+ sort_order=sort_order,
+ request_options=request_options,
+ )
+ return _response.data
+
+ def get_comment_thread(
+ self,
+ site_id: str,
+ comment_thread_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = 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.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ 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",
+ offset=1,
+ limit=1,
+ sort_by="createdOn",
+ sort_order="asc",
+ )
+ """
+ _response = self._raw_client.get_comment_thread(
+ site_id,
+ comment_thread_id,
+ locale_id=locale_id,
+ offset=offset,
+ limit=limit,
+ sort_by=sort_by,
+ sort_order=sort_order,
+ request_options=request_options,
+ )
+ return _response.data
+
+ def list_comment_replies(
+ self,
+ site_id: str,
+ comment_thread_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = 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.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ 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",
+ offset=1,
+ limit=1,
+ sort_by="createdOn",
+ sort_order="asc",
+ )
+ """
+ _response = self._raw_client.list_comment_replies(
+ site_id,
+ comment_thread_id,
+ locale_id=locale_id,
+ offset=offset,
+ limit=limit,
+ sort_by=sort_by,
+ sort_order=sort_order,
+ request_options=request_options,
+ )
+ return _response.data
+
+
+class AsyncCommentsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._raw_client = AsyncRawCommentsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawCommentsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawCommentsClient
+ """
+ return self._raw_client
+
+ async def list_comment_threads(
+ self,
+ site_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = 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.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ 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",
+ offset=1,
+ limit=1,
+ sort_by="createdOn",
+ sort_order="asc",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.list_comment_threads(
+ site_id,
+ locale_id=locale_id,
+ offset=offset,
+ limit=limit,
+ sort_by=sort_by,
+ sort_order=sort_order,
+ request_options=request_options,
+ )
+ return _response.data
+
+ async def get_comment_thread(
+ self,
+ site_id: str,
+ comment_thread_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = 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.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ 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",
+ offset=1,
+ limit=1,
+ sort_by="createdOn",
+ sort_order="asc",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.get_comment_thread(
+ site_id,
+ comment_thread_id,
+ locale_id=locale_id,
+ offset=offset,
+ limit=limit,
+ sort_by=sort_by,
+ sort_order=sort_order,
+ request_options=request_options,
+ )
+ return _response.data
+
+ async def list_comment_replies(
+ self,
+ site_id: str,
+ comment_thread_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = 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.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ 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",
+ offset=1,
+ limit=1,
+ sort_by="createdOn",
+ sort_order="asc",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.list_comment_replies(
+ site_id,
+ comment_thread_id,
+ locale_id=locale_id,
+ offset=offset,
+ limit=limit,
+ sort_by=sort_by,
+ sort_order=sort_order,
+ request_options=request_options,
+ )
+ return _response.data
diff --git a/src/webflow/resources/sites/resources/comments/raw_client.py b/src/webflow/resources/sites/resources/comments/raw_client.py
new file mode 100644
index 0000000..9502f35
--- /dev/null
+++ b/src/webflow/resources/sites/resources/comments/raw_client.py
@@ -0,0 +1,876 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from .....core.api_error import ApiError
+from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .....core.http_response import AsyncHttpResponse, HttpResponse
+from .....core.jsonable_encoder import jsonable_encoder
+from .....core.parse_error import ParsingError
+from .....core.pydantic_utilities import parse_obj_as
+from .....core.request_options import RequestOptions
+from .....errors.bad_request_error import BadRequestError
+from .....errors.internal_server_error import InternalServerError
+from .....errors.not_found_error import NotFoundError
+from .....errors.too_many_requests_error import TooManyRequestsError
+from .....errors.unauthorized_error import UnauthorizedError
+from .....types.comment_reply_list import CommentReplyList
+from .....types.comment_thread import CommentThread
+from .....types.comment_thread_list import CommentThreadList
+from .....types.error import Error
+from .types.comments_get_comment_thread_request_sort_by import CommentsGetCommentThreadRequestSortBy
+from .types.comments_get_comment_thread_request_sort_order import CommentsGetCommentThreadRequestSortOrder
+from .types.comments_list_comment_replies_request_sort_by import CommentsListCommentRepliesRequestSortBy
+from .types.comments_list_comment_replies_request_sort_order import CommentsListCommentRepliesRequestSortOrder
+from .types.comments_list_comment_threads_request_sort_by import CommentsListCommentThreadsRequestSortBy
+from .types.comments_list_comment_threads_request_sort_order import CommentsListCommentThreadsRequestSortOrder
+from pydantic import ValidationError
+
+
+class RawCommentsClient:
+ 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[int] = None,
+ limit: typing.Optional[int] = None,
+ sort_by: typing.Optional[CommentsListCommentThreadsRequestSortBy] = None,
+ sort_order: typing.Optional[CommentsListCommentThreadsRequestSortOrder] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[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.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ 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
+ -------
+ HttpResponse[CommentThreadList]
+ Request was successful
+ """
+ _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:
+ _data = typing.cast(
+ CommentThreadList,
+ parse_obj_as(
+ type_=CommentThreadList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def get_comment_thread(
+ self,
+ site_id: str,
+ comment_thread_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ sort_by: typing.Optional[CommentsGetCommentThreadRequestSortBy] = None,
+ sort_order: typing.Optional[CommentsGetCommentThreadRequestSortOrder] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[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.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ 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
+ -------
+ HttpResponse[CommentThread]
+ Request was successful
+ """
+ _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:
+ _data = typing.cast(
+ CommentThread,
+ parse_obj_as(
+ type_=CommentThread, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def list_comment_replies(
+ self,
+ site_id: str,
+ comment_thread_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ sort_by: typing.Optional[CommentsListCommentRepliesRequestSortBy] = None,
+ sort_order: typing.Optional[CommentsListCommentRepliesRequestSortOrder] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[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.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ 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
+ -------
+ HttpResponse[CommentReplyList]
+ Request was successful
+ """
+ _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:
+ _data = typing.cast(
+ CommentReplyList,
+ parse_obj_as(
+ type_=CommentReplyList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawCommentsClient:
+ 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[int] = None,
+ limit: typing.Optional[int] = None,
+ sort_by: typing.Optional[CommentsListCommentThreadsRequestSortBy] = None,
+ sort_order: typing.Optional[CommentsListCommentThreadsRequestSortOrder] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[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.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ 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
+ -------
+ AsyncHttpResponse[CommentThreadList]
+ Request was successful
+ """
+ _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:
+ _data = typing.cast(
+ CommentThreadList,
+ parse_obj_as(
+ type_=CommentThreadList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def get_comment_thread(
+ self,
+ site_id: str,
+ comment_thread_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ sort_by: typing.Optional[CommentsGetCommentThreadRequestSortBy] = None,
+ sort_order: typing.Optional[CommentsGetCommentThreadRequestSortOrder] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[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.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ 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
+ -------
+ AsyncHttpResponse[CommentThread]
+ Request was successful
+ """
+ _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:
+ _data = typing.cast(
+ CommentThread,
+ parse_obj_as(
+ type_=CommentThread, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def list_comment_replies(
+ self,
+ site_id: str,
+ comment_thread_id: str,
+ *,
+ locale_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ sort_by: typing.Optional[CommentsListCommentRepliesRequestSortBy] = None,
+ sort_order: typing.Optional[CommentsListCommentRepliesRequestSortOrder] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[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.
+
+ [Lear more about localization.](/data/v2.0.0/docs/working-with-localization)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ 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
+ -------
+ AsyncHttpResponse[CommentReplyList]
+ Request was successful
+ """
+ _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:
+ _data = typing.cast(
+ CommentReplyList,
+ parse_obj_as(
+ type_=CommentReplyList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/sites/resources/comments/types/__init__.py b/src/webflow/resources/sites/resources/comments/types/__init__.py
new file mode 100644
index 0000000..47e7b8b
--- /dev/null
+++ b/src/webflow/resources/sites/resources/comments/types/__init__.py
@@ -0,0 +1,53 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .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
+_dynamic_imports: typing.Dict[str, str] = {
+ "CommentsGetCommentThreadRequestSortBy": ".comments_get_comment_thread_request_sort_by",
+ "CommentsGetCommentThreadRequestSortOrder": ".comments_get_comment_thread_request_sort_order",
+ "CommentsListCommentRepliesRequestSortBy": ".comments_list_comment_replies_request_sort_by",
+ "CommentsListCommentRepliesRequestSortOrder": ".comments_list_comment_replies_request_sort_order",
+ "CommentsListCommentThreadsRequestSortBy": ".comments_list_comment_threads_request_sort_by",
+ "CommentsListCommentThreadsRequestSortOrder": ".comments_list_comment_threads_request_sort_order",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = [
+ "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/forms/__init__.py b/src/webflow/resources/sites/resources/forms/__init__.py
new file mode 100644
index 0000000..5cde020
--- /dev/null
+++ b/src/webflow/resources/sites/resources/forms/__init__.py
@@ -0,0 +1,4 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
diff --git a/src/webflow/resources/sites/resources/forms/client.py b/src/webflow/resources/sites/resources/forms/client.py
new file mode 100644
index 0000000..c165d82
--- /dev/null
+++ b/src/webflow/resources/sites/resources/forms/client.py
@@ -0,0 +1,578 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .....core.request_options import RequestOptions
+from .....types.form_submission import FormSubmission
+from .....types.form_submission_list import FormSubmissionList
+from .raw_client import AsyncRawFormsClient, RawFormsClient
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class FormsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._raw_client = RawFormsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawFormsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawFormsClient
+ """
+ return self._raw_client
+
+ def list_submissions_by_site(
+ self,
+ site_id: str,
+ *,
+ element_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> FormSubmissionList:
+ """
+ List all form submissions for a given site with the ability to filter submissions by a centralized `elementId`.
+
+ Add `elementId` when you want to filter form submissions to a specific form in a site. You can get the `elementId` from the [List forms endpoint](/data/reference/forms/forms/list) (displayed as `formElementId` in the response).
+
+
+ When a form is used in a Webflow component definition, each instance of the component will yield a unique form. Adding the `elementId` in this request ensures this API response includes all submissions from that core form, wherever that form is used in instantiated components.
+
+
+ Use the [List Form Submissions endpoint](/data/reference/forms/form-submissions/list-submissions) to list form submissions for a given form ID.
+
+ 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[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ FormSubmissionList
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.sites.forms.list_submissions_by_site(
+ site_id="580e63e98c9a982ac9b8b741",
+ element_id="18259716-3e5a-646a-5f41-5dc4b9405aa0",
+ offset=1,
+ limit=1,
+ )
+ """
+ _response = self._raw_client.list_submissions_by_site(
+ site_id, element_id=element_id, offset=offset, limit=limit, request_options=request_options
+ )
+ return _response.data
+
+ def list_submissions(
+ self,
+ site_id: str,
+ form_id: str,
+ *,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> FormSubmissionList:
+ """
+ List form submissions for a given form ID within a specific site.
+
+ Use the [List Form Submissions by Site endpoint](/data/reference/forms/form-submissions/list-submissions-by-site) to list form submissions for a given site with the ability to filter by a `formElementId`.
+
+ Required scope | `forms:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ form_id : str
+ Unique identifier for a Form
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ FormSubmissionList
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.sites.forms.list_submissions(
+ site_id="580e63e98c9a982ac9b8b741",
+ form_id="580e63e98c9a982ac9b8b741",
+ offset=1,
+ limit=1,
+ )
+ """
+ _response = self._raw_client.list_submissions(
+ site_id, form_id, offset=offset, limit=limit, request_options=request_options
+ )
+ return _response.data
+
+ def get_submission(
+ self, site_id: str, form_submission_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> FormSubmission:
+ """
+ Get information about a form submission within a specific site.
+
+ Required scope | `forms:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ form_submission_id : str
+ Unique identifier for a Form Submission
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ FormSubmission
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.sites.forms.get_submission(
+ site_id="580e63e98c9a982ac9b8b741",
+ form_submission_id="580e63e98c9a982ac9b8b741",
+ )
+ """
+ _response = self._raw_client.get_submission(site_id, form_submission_id, request_options=request_options)
+ return _response.data
+
+ def delete_submission(
+ self, site_id: str, form_submission_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> None:
+ """
+ Delete a form submission within a specific site.
+
+ Required scope | `forms:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ 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.sites.forms.delete_submission(
+ site_id="580e63e98c9a982ac9b8b741",
+ form_submission_id="580e63e98c9a982ac9b8b741",
+ )
+ """
+ _response = self._raw_client.delete_submission(site_id, form_submission_id, request_options=request_options)
+ return _response.data
+
+ def update_submission(
+ self,
+ site_id: str,
+ form_submission_id: str,
+ *,
+ form_submission_data: typing.Optional[typing.Dict[str, typing.Any]] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> FormSubmission:
+ """
+ Update hidden fields on a form submission within a specific site.
+
+ Required scope | `forms:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ form_submission_id : str
+ Unique identifier for a Form Submission
+
+ form_submission_data : typing.Optional[typing.Dict[str, typing.Any]]
+ An existing **hidden field** defined on the form schema, and the corresponding value to set
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ FormSubmission
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.sites.forms.update_submission(
+ site_id="580e63e98c9a982ac9b8b741",
+ form_submission_id="580e63e98c9a982ac9b8b741",
+ )
+ """
+ _response = self._raw_client.update_submission(
+ site_id, form_submission_id, form_submission_data=form_submission_data, request_options=request_options
+ )
+ return _response.data
+
+
+class AsyncFormsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._raw_client = AsyncRawFormsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawFormsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawFormsClient
+ """
+ return self._raw_client
+
+ async def list_submissions_by_site(
+ self,
+ site_id: str,
+ *,
+ element_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> FormSubmissionList:
+ """
+ List all form submissions for a given site with the ability to filter submissions by a centralized `elementId`.
+
+ Add `elementId` when you want to filter form submissions to a specific form in a site. You can get the `elementId` from the [List forms endpoint](/data/reference/forms/forms/list) (displayed as `formElementId` in the response).
+
+
+ When a form is used in a Webflow component definition, each instance of the component will yield a unique form. Adding the `elementId` in this request ensures this API response includes all submissions from that core form, wherever that form is used in instantiated components.
+
+
+ Use the [List Form Submissions endpoint](/data/reference/forms/form-submissions/list-submissions) to list form submissions for a given form ID.
+
+ 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[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ FormSubmissionList
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.sites.forms.list_submissions_by_site(
+ site_id="580e63e98c9a982ac9b8b741",
+ element_id="18259716-3e5a-646a-5f41-5dc4b9405aa0",
+ offset=1,
+ limit=1,
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.list_submissions_by_site(
+ site_id, element_id=element_id, offset=offset, limit=limit, request_options=request_options
+ )
+ return _response.data
+
+ async def list_submissions(
+ self,
+ site_id: str,
+ form_id: str,
+ *,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> FormSubmissionList:
+ """
+ List form submissions for a given form ID within a specific site.
+
+ Use the [List Form Submissions by Site endpoint](/data/reference/forms/form-submissions/list-submissions-by-site) to list form submissions for a given site with the ability to filter by a `formElementId`.
+
+ Required scope | `forms:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ form_id : str
+ Unique identifier for a Form
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ 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.sites.forms.list_submissions(
+ site_id="580e63e98c9a982ac9b8b741",
+ form_id="580e63e98c9a982ac9b8b741",
+ offset=1,
+ limit=1,
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.list_submissions(
+ site_id, form_id, offset=offset, limit=limit, request_options=request_options
+ )
+ return _response.data
+
+ async def get_submission(
+ self, site_id: str, form_submission_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> FormSubmission:
+ """
+ Get information about a form submission within a specific site.
+
+ Required scope | `forms:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ form_submission_id : str
+ Unique identifier for a Form Submission
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ FormSubmission
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.sites.forms.get_submission(
+ site_id="580e63e98c9a982ac9b8b741",
+ form_submission_id="580e63e98c9a982ac9b8b741",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.get_submission(site_id, form_submission_id, request_options=request_options)
+ return _response.data
+
+ async def delete_submission(
+ self, site_id: str, form_submission_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> None:
+ """
+ Delete a form submission within a specific site.
+
+ Required scope | `forms:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ 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.sites.forms.delete_submission(
+ site_id="580e63e98c9a982ac9b8b741",
+ form_submission_id="580e63e98c9a982ac9b8b741",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.delete_submission(
+ site_id, form_submission_id, request_options=request_options
+ )
+ return _response.data
+
+ async def update_submission(
+ self,
+ site_id: str,
+ form_submission_id: str,
+ *,
+ form_submission_data: typing.Optional[typing.Dict[str, typing.Any]] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> FormSubmission:
+ """
+ Update hidden fields on a form submission within a specific site.
+
+ Required scope | `forms:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ form_submission_id : str
+ Unique identifier for a Form Submission
+
+ form_submission_data : typing.Optional[typing.Dict[str, typing.Any]]
+ An existing **hidden field** defined on the form schema, and the corresponding value to set
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ FormSubmission
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.sites.forms.update_submission(
+ site_id="580e63e98c9a982ac9b8b741",
+ form_submission_id="580e63e98c9a982ac9b8b741",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.update_submission(
+ site_id, form_submission_id, form_submission_data=form_submission_data, request_options=request_options
+ )
+ return _response.data
diff --git a/src/webflow/resources/sites/resources/forms/raw_client.py b/src/webflow/resources/sites/resources/forms/raw_client.py
new file mode 100644
index 0000000..c295236
--- /dev/null
+++ b/src/webflow/resources/sites/resources/forms/raw_client.py
@@ -0,0 +1,1330 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from .....core.api_error import ApiError
+from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .....core.http_response import AsyncHttpResponse, HttpResponse
+from .....core.jsonable_encoder import jsonable_encoder
+from .....core.parse_error import ParsingError
+from .....core.pydantic_utilities import parse_obj_as
+from .....core.request_options import RequestOptions
+from .....errors.bad_request_error import BadRequestError
+from .....errors.conflict_error import ConflictError
+from .....errors.forbidden_error import ForbiddenError
+from .....errors.internal_server_error import InternalServerError
+from .....errors.not_found_error import NotFoundError
+from .....errors.too_many_requests_error import TooManyRequestsError
+from .....errors.unauthorized_error import UnauthorizedError
+from .....types.error import Error
+from .....types.form_submission import FormSubmission
+from .....types.form_submission_list import FormSubmissionList
+from pydantic import ValidationError
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RawFormsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def list_submissions_by_site(
+ self,
+ site_id: str,
+ *,
+ element_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[FormSubmissionList]:
+ """
+ List all form submissions for a given site with the ability to filter submissions by a centralized `elementId`.
+
+ Add `elementId` when you want to filter form submissions to a specific form in a site. You can get the `elementId` from the [List forms endpoint](/data/reference/forms/forms/list) (displayed as `formElementId` in the response).
+
+
+ When a form is used in a Webflow component definition, each instance of the component will yield a unique form. Adding the `elementId` in this request ensures this API response includes all submissions from that core form, wherever that form is used in instantiated components.
+
+
+ Use the [List Form Submissions endpoint](/data/reference/forms/form-submissions/list-submissions) to list form submissions for a given form ID.
+
+ 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[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[FormSubmissionList]
+ Request was successful
+ """
+ _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:
+ _data = typing.cast(
+ FormSubmissionList,
+ parse_obj_as(
+ type_=FormSubmissionList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def list_submissions(
+ self,
+ site_id: str,
+ form_id: str,
+ *,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[FormSubmissionList]:
+ """
+ List form submissions for a given form ID within a specific site.
+
+ Use the [List Form Submissions by Site endpoint](/data/reference/forms/form-submissions/list-submissions-by-site) to list form submissions for a given site with the ability to filter by a `formElementId`.
+
+ Required scope | `forms:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ form_id : str
+ Unique identifier for a Form
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[FormSubmissionList]
+ Request was successful
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"sites/{jsonable_encoder(site_id)}/forms/{jsonable_encoder(form_id)}/submissions",
+ base_url=self._client_wrapper.get_environment().base,
+ method="GET",
+ params={
+ "offset": offset,
+ "limit": limit,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ FormSubmissionList,
+ parse_obj_as(
+ type_=FormSubmissionList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def get_submission(
+ self, site_id: str, form_submission_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[FormSubmission]:
+ """
+ Get information about a form submission within a specific site.
+
+ Required scope | `forms:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ form_submission_id : str
+ Unique identifier for a Form Submission
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[FormSubmission]
+ Request was successful
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"sites/{jsonable_encoder(site_id)}/form_submissions/{jsonable_encoder(form_submission_id)}",
+ base_url=self._client_wrapper.get_environment().base,
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ FormSubmission,
+ parse_obj_as(
+ type_=FormSubmission, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def delete_submission(
+ self, site_id: str, form_submission_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[None]:
+ """
+ Delete a form submission within a specific site.
+
+ Required scope | `forms:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ form_submission_id : str
+ Unique identifier for a Form Submission
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[None]
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"sites/{jsonable_encoder(site_id)}/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 HttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def update_submission(
+ self,
+ site_id: str,
+ form_submission_id: str,
+ *,
+ form_submission_data: typing.Optional[typing.Dict[str, typing.Any]] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[FormSubmission]:
+ """
+ Update hidden fields on a form submission within a specific site.
+
+ Required scope | `forms:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ form_submission_id : str
+ Unique identifier for a Form Submission
+
+ form_submission_data : typing.Optional[typing.Dict[str, typing.Any]]
+ An existing **hidden field** defined on the form schema, and the corresponding value to set
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[FormSubmission]
+ Request was successful
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"sites/{jsonable_encoder(site_id)}/form_submissions/{jsonable_encoder(form_submission_id)}",
+ base_url=self._client_wrapper.get_environment().base,
+ method="PATCH",
+ json={
+ "formSubmissionData": form_submission_data,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ FormSubmission,
+ parse_obj_as(
+ type_=FormSubmission, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawFormsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def list_submissions_by_site(
+ self,
+ site_id: str,
+ *,
+ element_id: typing.Optional[str] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[FormSubmissionList]:
+ """
+ List all form submissions for a given site with the ability to filter submissions by a centralized `elementId`.
+
+ Add `elementId` when you want to filter form submissions to a specific form in a site. You can get the `elementId` from the [List forms endpoint](/data/reference/forms/forms/list) (displayed as `formElementId` in the response).
+
+
+ When a form is used in a Webflow component definition, each instance of the component will yield a unique form. Adding the `elementId` in this request ensures this API response includes all submissions from that core form, wherever that form is used in instantiated components.
+
+
+ Use the [List Form Submissions endpoint](/data/reference/forms/form-submissions/list-submissions) to list form submissions for a given form ID.
+
+ 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[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[FormSubmissionList]
+ Request was successful
+ """
+ _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:
+ _data = typing.cast(
+ FormSubmissionList,
+ parse_obj_as(
+ type_=FormSubmissionList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def list_submissions(
+ self,
+ site_id: str,
+ form_id: str,
+ *,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[FormSubmissionList]:
+ """
+ List form submissions for a given form ID within a specific site.
+
+ Use the [List Form Submissions by Site endpoint](/data/reference/forms/form-submissions/list-submissions-by-site) to list form submissions for a given site with the ability to filter by a `formElementId`.
+
+ Required scope | `forms:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ form_id : str
+ Unique identifier for a Form
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[FormSubmissionList]
+ Request was successful
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"sites/{jsonable_encoder(site_id)}/forms/{jsonable_encoder(form_id)}/submissions",
+ base_url=self._client_wrapper.get_environment().base,
+ method="GET",
+ params={
+ "offset": offset,
+ "limit": limit,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ FormSubmissionList,
+ parse_obj_as(
+ type_=FormSubmissionList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def get_submission(
+ self, site_id: str, form_submission_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[FormSubmission]:
+ """
+ Get information about a form submission within a specific site.
+
+ Required scope | `forms:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ form_submission_id : str
+ Unique identifier for a Form Submission
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[FormSubmission]
+ Request was successful
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"sites/{jsonable_encoder(site_id)}/form_submissions/{jsonable_encoder(form_submission_id)}",
+ base_url=self._client_wrapper.get_environment().base,
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ FormSubmission,
+ parse_obj_as(
+ type_=FormSubmission, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def delete_submission(
+ self, site_id: str, form_submission_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[None]:
+ """
+ Delete a form submission within a specific site.
+
+ Required scope | `forms:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ form_submission_id : str
+ Unique identifier for a Form Submission
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[None]
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"sites/{jsonable_encoder(site_id)}/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 AsyncHttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def update_submission(
+ self,
+ site_id: str,
+ form_submission_id: str,
+ *,
+ form_submission_data: typing.Optional[typing.Dict[str, typing.Any]] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[FormSubmission]:
+ """
+ Update hidden fields on a form submission within a specific site.
+
+ Required scope | `forms:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ form_submission_id : str
+ Unique identifier for a Form Submission
+
+ form_submission_data : typing.Optional[typing.Dict[str, typing.Any]]
+ An existing **hidden field** defined on the form schema, and the corresponding value to set
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[FormSubmission]
+ Request was successful
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"sites/{jsonable_encoder(site_id)}/form_submissions/{jsonable_encoder(form_submission_id)}",
+ base_url=self._client_wrapper.get_environment().base,
+ method="PATCH",
+ json={
+ "formSubmissionData": form_submission_data,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ FormSubmission,
+ parse_obj_as(
+ type_=FormSubmission, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/sites/resources/plans/__init__.py b/src/webflow/resources/sites/resources/plans/__init__.py
new file mode 100644
index 0000000..5cde020
--- /dev/null
+++ b/src/webflow/resources/sites/resources/plans/__init__.py
@@ -0,0 +1,4 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
diff --git a/src/webflow/resources/sites/resources/plans/client.py b/src/webflow/resources/sites/resources/plans/client.py
new file mode 100644
index 0000000..b9b9d0a
--- /dev/null
+++ b/src/webflow/resources/sites/resources/plans/client.py
@@ -0,0 +1,118 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .....core.request_options import RequestOptions
+from .....types.site_plan import SitePlan
+from .raw_client import AsyncRawPlansClient, RawPlansClient
+
+
+class PlansClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._raw_client = RawPlansClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawPlansClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawPlansClient
+ """
+ return self._raw_client
+
+ def get_site_plan(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> SitePlan:
+ """
+ Get site plan details for the specified Site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope | `sites:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ SitePlan
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.sites.plans.get_site_plan(
+ site_id="580e63e98c9a982ac9b8b741",
+ )
+ """
+ _response = self._raw_client.get_site_plan(site_id, request_options=request_options)
+ return _response.data
+
+
+class AsyncPlansClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._raw_client = AsyncRawPlansClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawPlansClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawPlansClient
+ """
+ return self._raw_client
+
+ async def get_site_plan(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> SitePlan:
+ """
+ Get site plan details for the specified Site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope | `sites:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ SitePlan
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.sites.plans.get_site_plan(
+ site_id="580e63e98c9a982ac9b8b741",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.get_site_plan(site_id, request_options=request_options)
+ return _response.data
diff --git a/src/webflow/resources/sites/resources/plans/raw_client.py b/src/webflow/resources/sites/resources/plans/raw_client.py
new file mode 100644
index 0000000..c6f7bad
--- /dev/null
+++ b/src/webflow/resources/sites/resources/plans/raw_client.py
@@ -0,0 +1,236 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from .....core.api_error import ApiError
+from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .....core.http_response import AsyncHttpResponse, HttpResponse
+from .....core.jsonable_encoder import jsonable_encoder
+from .....core.parse_error import ParsingError
+from .....core.pydantic_utilities import parse_obj_as
+from .....core.request_options import RequestOptions
+from .....errors.bad_request_error import BadRequestError
+from .....errors.internal_server_error import InternalServerError
+from .....errors.not_found_error import NotFoundError
+from .....errors.too_many_requests_error import TooManyRequestsError
+from .....errors.unauthorized_error import UnauthorizedError
+from .....types.error import Error
+from .....types.site_plan import SitePlan
+from pydantic import ValidationError
+
+
+class RawPlansClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def get_site_plan(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[SitePlan]:
+ """
+ Get site plan details for the specified Site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope | `sites:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[SitePlan]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ SitePlan,
+ parse_obj_as(
+ type_=SitePlan, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawPlansClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def get_site_plan(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[SitePlan]:
+ """
+ Get site plan details for the specified Site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope | `sites:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[SitePlan]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ SitePlan,
+ parse_obj_as(
+ type_=SitePlan, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/sites/resources/redirects/__init__.py b/src/webflow/resources/sites/resources/redirects/__init__.py
new file mode 100644
index 0000000..5cde020
--- /dev/null
+++ b/src/webflow/resources/sites/resources/redirects/__init__.py
@@ -0,0 +1,4 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
diff --git a/src/webflow/resources/sites/resources/redirects/client.py b/src/webflow/resources/sites/resources/redirects/client.py
new file mode 100644
index 0000000..c2e1f7d
--- /dev/null
+++ b/src/webflow/resources/sites/resources/redirects/client.py
@@ -0,0 +1,478 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .....core.request_options import RequestOptions
+from .....types.redirect import Redirect
+from .....types.redirects import Redirects
+from .raw_client import AsyncRawRedirectsClient, RawRedirectsClient
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RedirectsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._raw_client = RawRedirectsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawRedirectsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawRedirectsClient
+ """
+ return self._raw_client
+
+ def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Redirects:
+ """
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Redirects
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.sites.redirects.list(
+ site_id="580e63e98c9a982ac9b8b741",
+ )
+ """
+ _response = self._raw_client.list(site_id, request_options=request_options)
+ return _response.data
+
+ def create(
+ self,
+ site_id: str,
+ *,
+ id: typing.Optional[str] = OMIT,
+ from_url: typing.Optional[str] = OMIT,
+ to_url: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> Redirect:
+ """
+ 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
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ id : typing.Optional[str]
+ The ID of the specific redirect rule
+
+ from_url : typing.Optional[str]
+ The source URL path that will be redirected.
+
+ to_url : typing.Optional[str]
+ The target URL path where the user or client will be redirected.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Redirect
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.sites.redirects.create(
+ site_id="580e63e98c9a982ac9b8b741",
+ id="42e1a2b7aa1a13f768a0042a",
+ from_url="/mostly-harmless",
+ to_url="/earth",
+ )
+ """
+ _response = self._raw_client.create(
+ site_id, id=id, from_url=from_url, to_url=to_url, request_options=request_options
+ )
+ return _response.data
+
+ def delete(
+ self, site_id: str, redirect_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> Redirects:
+ """
+ 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
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ redirect_id : str
+ Unique identifier site redirect
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Redirects
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.sites.redirects.delete(
+ site_id="580e63e98c9a982ac9b8b741",
+ redirect_id="66c4cb9a20cac35ed19500e6",
+ )
+ """
+ _response = self._raw_client.delete(site_id, redirect_id, request_options=request_options)
+ return _response.data
+
+ def update(
+ self,
+ site_id: str,
+ redirect_id: str,
+ *,
+ id: typing.Optional[str] = OMIT,
+ from_url: typing.Optional[str] = OMIT,
+ to_url: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> Redirect:
+ """
+ Update a 301 redirection rule from a site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope: `sites:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ redirect_id : str
+ Unique identifier site redirect
+
+ id : typing.Optional[str]
+ The ID of the specific redirect rule
+
+ from_url : typing.Optional[str]
+ The source URL path that will be redirected.
+
+ to_url : typing.Optional[str]
+ The target URL path where the user or client will be redirected.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Redirect
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
+
+ client = Webflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+ client.sites.redirects.update(
+ site_id="580e63e98c9a982ac9b8b741",
+ redirect_id="66c4cb9a20cac35ed19500e6",
+ id="42e1a2b7aa1a13f768a0042a",
+ from_url="/mostly-harmless",
+ to_url="/earth",
+ )
+ """
+ _response = self._raw_client.update(
+ site_id, redirect_id, id=id, from_url=from_url, to_url=to_url, request_options=request_options
+ )
+ return _response.data
+
+
+class AsyncRedirectsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._raw_client = AsyncRawRedirectsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawRedirectsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawRedirectsClient
+ """
+ return self._raw_client
+
+ async def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Redirects:
+ """
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Redirects
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.sites.redirects.list(
+ site_id="580e63e98c9a982ac9b8b741",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.list(site_id, request_options=request_options)
+ return _response.data
+
+ async def create(
+ self,
+ site_id: str,
+ *,
+ id: typing.Optional[str] = OMIT,
+ from_url: typing.Optional[str] = OMIT,
+ to_url: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> Redirect:
+ """
+ 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
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ id : typing.Optional[str]
+ The ID of the specific redirect rule
+
+ from_url : typing.Optional[str]
+ The source URL path that will be redirected.
+
+ to_url : typing.Optional[str]
+ The target URL path where the user or client will be redirected.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Redirect
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.sites.redirects.create(
+ site_id="580e63e98c9a982ac9b8b741",
+ id="42e1a2b7aa1a13f768a0042a",
+ from_url="/mostly-harmless",
+ to_url="/earth",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.create(
+ site_id, id=id, from_url=from_url, to_url=to_url, request_options=request_options
+ )
+ return _response.data
+
+ async def delete(
+ self, site_id: str, redirect_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> Redirects:
+ """
+ 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
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ redirect_id : str
+ Unique identifier site redirect
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Redirects
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.sites.redirects.delete(
+ site_id="580e63e98c9a982ac9b8b741",
+ redirect_id="66c4cb9a20cac35ed19500e6",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.delete(site_id, redirect_id, request_options=request_options)
+ return _response.data
+
+ async def update(
+ self,
+ site_id: str,
+ redirect_id: str,
+ *,
+ id: typing.Optional[str] = OMIT,
+ from_url: typing.Optional[str] = OMIT,
+ to_url: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> Redirect:
+ """
+ Update a 301 redirection rule from a site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope: `sites:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ redirect_id : str
+ Unique identifier site redirect
+
+ id : typing.Optional[str]
+ The ID of the specific redirect rule
+
+ from_url : typing.Optional[str]
+ The source URL path that will be redirected.
+
+ to_url : typing.Optional[str]
+ The target URL path where the user or client will be redirected.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Redirect
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
+
+ client = AsyncWebflow(
+ access_token="YOUR_ACCESS_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.sites.redirects.update(
+ site_id="580e63e98c9a982ac9b8b741",
+ redirect_id="66c4cb9a20cac35ed19500e6",
+ id="42e1a2b7aa1a13f768a0042a",
+ from_url="/mostly-harmless",
+ to_url="/earth",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.update(
+ site_id, redirect_id, id=id, from_url=from_url, to_url=to_url, request_options=request_options
+ )
+ return _response.data
diff --git a/src/webflow/resources/sites/resources/redirects/raw_client.py b/src/webflow/resources/sites/resources/redirects/raw_client.py
new file mode 100644
index 0000000..d5abafe
--- /dev/null
+++ b/src/webflow/resources/sites/resources/redirects/raw_client.py
@@ -0,0 +1,978 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from .....core.api_error import ApiError
+from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .....core.http_response import AsyncHttpResponse, HttpResponse
+from .....core.jsonable_encoder import jsonable_encoder
+from .....core.parse_error import ParsingError
+from .....core.pydantic_utilities import parse_obj_as
+from .....core.request_options import RequestOptions
+from .....errors.bad_request_error import BadRequestError
+from .....errors.internal_server_error import InternalServerError
+from .....errors.not_found_error import NotFoundError
+from .....errors.too_many_requests_error import TooManyRequestsError
+from .....errors.unauthorized_error import UnauthorizedError
+from .....types.error import Error
+from .....types.redirect import Redirect
+from .....types.redirects import Redirects
+from pydantic import ValidationError
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RawRedirectsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[Redirects]:
+ """
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Redirects]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Redirects,
+ parse_obj_as(
+ type_=Redirects, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def create(
+ self,
+ site_id: str,
+ *,
+ id: typing.Optional[str] = OMIT,
+ from_url: typing.Optional[str] = OMIT,
+ to_url: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[Redirect]:
+ """
+ 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
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ id : typing.Optional[str]
+ The ID of the specific redirect rule
+
+ from_url : typing.Optional[str]
+ The source URL path that will be redirected.
+
+ to_url : typing.Optional[str]
+ The target URL path where the user or client will be redirected.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Redirect]
+ Request was successful
+ """
+ _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,
+ "fromUrl": from_url,
+ "toUrl": to_url,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Redirect,
+ parse_obj_as(
+ type_=Redirect, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def delete(
+ self, site_id: str, redirect_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[Redirects]:
+ """
+ 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
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ redirect_id : str
+ Unique identifier site redirect
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Redirects]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Redirects,
+ parse_obj_as(
+ type_=Redirects, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def update(
+ self,
+ site_id: str,
+ redirect_id: str,
+ *,
+ id: typing.Optional[str] = OMIT,
+ from_url: typing.Optional[str] = OMIT,
+ to_url: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[Redirect]:
+ """
+ Update a 301 redirection rule from a site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope: `sites:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ redirect_id : str
+ Unique identifier site redirect
+
+ id : typing.Optional[str]
+ The ID of the specific redirect rule
+
+ from_url : typing.Optional[str]
+ The source URL path that will be redirected.
+
+ to_url : typing.Optional[str]
+ The target URL path where the user or client will be redirected.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Redirect]
+ Request was successful
+ """
+ _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,
+ "fromUrl": from_url,
+ "toUrl": to_url,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Redirect,
+ parse_obj_as(
+ type_=Redirect, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawRedirectsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def list(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[Redirects]:
+ """
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Redirects]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Redirects,
+ parse_obj_as(
+ type_=Redirects, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def create(
+ self,
+ site_id: str,
+ *,
+ id: typing.Optional[str] = OMIT,
+ from_url: typing.Optional[str] = OMIT,
+ to_url: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[Redirect]:
+ """
+ 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
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ id : typing.Optional[str]
+ The ID of the specific redirect rule
+
+ from_url : typing.Optional[str]
+ The source URL path that will be redirected.
+
+ to_url : typing.Optional[str]
+ The target URL path where the user or client will be redirected.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Redirect]
+ Request was successful
+ """
+ _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,
+ "fromUrl": from_url,
+ "toUrl": to_url,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Redirect,
+ parse_obj_as(
+ type_=Redirect, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def delete(
+ self, site_id: str, redirect_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[Redirects]:
+ """
+ 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
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ redirect_id : str
+ Unique identifier site redirect
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Redirects]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Redirects,
+ parse_obj_as(
+ type_=Redirects, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def update(
+ self,
+ site_id: str,
+ redirect_id: str,
+ *,
+ id: typing.Optional[str] = OMIT,
+ from_url: typing.Optional[str] = OMIT,
+ to_url: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[Redirect]:
+ """
+ Update a 301 redirection rule from a site.
+
+ This endpoint requires an Enterprise workspace.
+
+ Required scope: `sites:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ redirect_id : str
+ Unique identifier site redirect
+
+ id : typing.Optional[str]
+ The ID of the specific redirect rule
+
+ from_url : typing.Optional[str]
+ The source URL path that will be redirected.
+
+ to_url : typing.Optional[str]
+ The target URL path where the user or client will be redirected.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Redirect]
+ Request was successful
+ """
+ _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,
+ "fromUrl": from_url,
+ "toUrl": to_url,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Redirect,
+ parse_obj_as(
+ type_=Redirect, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/sites/resources/robots_txt/__init__.py b/src/webflow/resources/sites/resources/robots_txt/__init__.py
new file mode 100644
index 0000000..5cde020
--- /dev/null
+++ b/src/webflow/resources/sites/resources/robots_txt/__init__.py
@@ -0,0 +1,4 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
diff --git a/src/webflow/resources/sites/resources/robots_txt/client.py b/src/webflow/resources/sites/resources/robots_txt/client.py
new file mode 100644
index 0000000..af74b37
--- /dev/null
+++ b/src/webflow/resources/sites/resources/robots_txt/client.py
@@ -0,0 +1,486 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .....core.request_options import RequestOptions
+from .....types.robots import Robots
+from .....types.robots_rules_item import RobotsRulesItem
+from .raw_client import AsyncRawRobotsTxtClient, RawRobotsTxtClient
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RobotsTxtClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._raw_client = RawRobotsTxtClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawRobotsTxtClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawRobotsTxtClient
+ """
+ return self._raw_client
+
+ 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._raw_client.get(site_id, request_options=request_options)
+ return _response.data
+
+ 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._raw_client.put(site_id, rules=rules, sitemap=sitemap, request_options=request_options)
+ return _response.data
+
+ 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._raw_client.delete(site_id, rules=rules, sitemap=sitemap, request_options=request_options)
+ return _response.data
+
+ 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._raw_client.patch(site_id, rules=rules, sitemap=sitemap, request_options=request_options)
+ return _response.data
+
+
+class AsyncRobotsTxtClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._raw_client = AsyncRawRobotsTxtClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawRobotsTxtClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawRobotsTxtClient
+ """
+ return self._raw_client
+
+ 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._raw_client.get(site_id, request_options=request_options)
+ return _response.data
+
+ 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._raw_client.put(site_id, rules=rules, sitemap=sitemap, request_options=request_options)
+ return _response.data
+
+ 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._raw_client.delete(
+ site_id, rules=rules, sitemap=sitemap, request_options=request_options
+ )
+ return _response.data
+
+ 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._raw_client.patch(site_id, rules=rules, sitemap=sitemap, request_options=request_options)
+ return _response.data
diff --git a/src/webflow/resources/sites/resources/robots_txt/raw_client.py b/src/webflow/resources/sites/resources/robots_txt/raw_client.py
new file mode 100644
index 0000000..ac8d1fe
--- /dev/null
+++ b/src/webflow/resources/sites/resources/robots_txt/raw_client.py
@@ -0,0 +1,987 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from .....core.api_error import ApiError
+from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .....core.http_response import AsyncHttpResponse, HttpResponse
+from .....core.jsonable_encoder import jsonable_encoder
+from .....core.parse_error import ParsingError
+from .....core.pydantic_utilities import parse_obj_as
+from .....core.request_options import RequestOptions
+from .....core.serialization import convert_and_respect_annotation_metadata
+from .....errors.bad_request_error import BadRequestError
+from .....errors.internal_server_error import InternalServerError
+from .....errors.not_found_error import NotFoundError
+from .....errors.too_many_requests_error import TooManyRequestsError
+from .....errors.unauthorized_error import UnauthorizedError
+from .....types.error import Error
+from .....types.robots import Robots
+from .....types.robots_rules_item import RobotsRulesItem
+from pydantic import ValidationError
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RawRobotsTxtClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def get(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[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
+ -------
+ HttpResponse[Robots]
+ Request was successful
+ """
+ _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:
+ _data = typing.cast(
+ Robots,
+ parse_obj_as(
+ type_=Robots, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def put(
+ self,
+ site_id: str,
+ *,
+ rules: typing.Optional[typing.Sequence[RobotsRulesItem]] = OMIT,
+ sitemap: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[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
+ -------
+ HttpResponse[Robots]
+ Request was successful
+ """
+ _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,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Robots,
+ parse_obj_as(
+ type_=Robots, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def delete(
+ self,
+ site_id: str,
+ *,
+ rules: typing.Optional[typing.Sequence[RobotsRulesItem]] = OMIT,
+ sitemap: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[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
+ -------
+ HttpResponse[Robots]
+ Request was successful
+ """
+ _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,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Robots,
+ parse_obj_as(
+ type_=Robots, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def patch(
+ self,
+ site_id: str,
+ *,
+ rules: typing.Optional[typing.Sequence[RobotsRulesItem]] = OMIT,
+ sitemap: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[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
+ -------
+ HttpResponse[Robots]
+ Request was successful
+ """
+ _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,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Robots,
+ parse_obj_as(
+ type_=Robots, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawRobotsTxtClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def get(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[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
+ -------
+ AsyncHttpResponse[Robots]
+ Request was successful
+ """
+ _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:
+ _data = typing.cast(
+ Robots,
+ parse_obj_as(
+ type_=Robots, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def put(
+ self,
+ site_id: str,
+ *,
+ rules: typing.Optional[typing.Sequence[RobotsRulesItem]] = OMIT,
+ sitemap: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[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
+ -------
+ AsyncHttpResponse[Robots]
+ Request was successful
+ """
+ _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,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Robots,
+ parse_obj_as(
+ type_=Robots, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def delete(
+ self,
+ site_id: str,
+ *,
+ rules: typing.Optional[typing.Sequence[RobotsRulesItem]] = OMIT,
+ sitemap: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[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
+ -------
+ AsyncHttpResponse[Robots]
+ Request was successful
+ """
+ _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,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Robots,
+ parse_obj_as(
+ type_=Robots, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def patch(
+ self,
+ site_id: str,
+ *,
+ rules: typing.Optional[typing.Sequence[RobotsRulesItem]] = OMIT,
+ sitemap: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[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
+ -------
+ AsyncHttpResponse[Robots]
+ Request was successful
+ """
+ _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,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Robots,
+ parse_obj_as(
+ type_=Robots, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/sites/resources/scripts/__init__.py b/src/webflow/resources/sites/resources/scripts/__init__.py
index f3ea265..5cde020 100644
--- a/src/webflow/resources/sites/resources/scripts/__init__.py
+++ b/src/webflow/resources/sites/resources/scripts/__init__.py
@@ -1,2 +1,4 @@
# This file was auto-generated by Fern from our API Definition.
+# isort: skip_file
+
diff --git a/src/webflow/resources/sites/resources/scripts/client.py b/src/webflow/resources/sites/resources/scripts/client.py
index bca1824..f7cddec 100644
--- a/src/webflow/resources/sites/resources/scripts/client.py
+++ b/src/webflow/resources/sites/resources/scripts/client.py
@@ -1,26 +1,13 @@
# This file was auto-generated by Fern from our API Definition.
import typing
-import urllib.parse
-from json.decoder import JSONDecodeError
-from .....core.api_error import ApiError
from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from .....core.jsonable_encoder import jsonable_encoder
-from .....core.remove_none_from_dict import remove_none_from_dict
from .....core.request_options import RequestOptions
-from .....errors.bad_request_error import BadRequestError
-from .....errors.internal_server_error import InternalServerError
-from .....errors.not_found_error import NotFoundError
-from .....errors.too_many_requests_error import TooManyRequestsError
-from .....errors.unauthorized_error import UnauthorizedError
from .....types.list_custom_code_blocks import ListCustomCodeBlocks
+from .....types.script_apply import ScriptApply
from .....types.script_apply_list import ScriptApplyList
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+from .raw_client import AsyncRawScriptsClient, RawScriptsClient
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
@@ -28,567 +15,465 @@
class ScriptsClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = RawScriptsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawScriptsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawScriptsClient
+ """
+ return self._raw_client
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. Access to this endpoint requires a bearer token from a Data Client App. Required scope | `custom_code:read`
+ 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`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ScriptApplyList
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.sites.scripts.get_custom_code(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/custom_code"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(ScriptApplyList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.get_custom_code(site_id, request_options=request_options)
+ return _response.data
def upsert_custom_code(
- self, site_id: str, *, request: ScriptApplyList, request_options: typing.Optional[RequestOptions] = None
+ self,
+ site_id: str,
+ *,
+ scripts: typing.Optional[typing.Sequence[ScriptApply]] = OMIT,
+ last_updated: typing.Optional[str] = OMIT,
+ created_on: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
) -> ScriptApplyList:
"""
- 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. Required scope | `custom_code:write`
+ Apply registered scripts to a site. If you have multiple scripts your App needs to apply or maintain on a site, ensure they are always included in the request body for this endpoint. To remove individual scripts, simply call this endpoint without the script in the request body.
+
+
+ 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`
+
+ 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
- Parameters:
- - site_id: str. Unique identifier for a Site
+ created_on : typing.Optional[str]
+ Date when the Site's scripts were created
- - request: ScriptApplyList.
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow import ScriptApply, ScriptApplyList, ScriptApplyLocation
- from webflow.client import Webflow
+ Returns
+ -------
+ ScriptApplyList
+ Request was successful
+
+ Examples
+ --------
+ from webflow import ScriptApply, Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.sites.scripts.upsert_custom_code(
- site_id="site_id",
- request=ScriptApplyList(
- scripts=[
- ScriptApply(
- id="cms_slider",
- location=ScriptApplyLocation.HEADER,
- version="1.0.0",
- attributes={"my-attribute": "some-value"},
- ),
- ScriptApply(
- id="alert",
- location=ScriptApplyLocation.HEADER,
- version="0.0.1",
- ),
- ScriptApply(
- id="id",
- location=ScriptApplyLocation.HEADER,
- version="version",
- ),
- ],
- ),
+ 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",
+ ),
+ ],
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "PUT",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/custom_code"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.upsert_custom_code(
+ site_id, scripts=scripts, last_updated=last_updated, created_on=created_on, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(ScriptApplyList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
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. Required scope | `custom_code:write`
+ Remove all scripts from a site applied by the App. This endpoint will not remove scripts from the site's registered scripts.
+
+ To remove individual scripts applied by the App, use the [Add/Update Custom Code](/data/reference/custom-code/custom-code-sites/upsert-custom-code) endpoint.
+
+ Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app).
+
+ Required scope | `custom_code:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Returns
+ -------
+ None
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.sites.scripts.delete_custom_code(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "DELETE",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/custom_code"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.delete_custom_code(site_id, request_options=request_options)
+ return _response.data
def list_custom_code_blocks(
self,
site_id: str,
*,
- offset: typing.Optional[float] = None,
- limit: typing.Optional[float] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> ListCustomCodeBlocks:
"""
- Get all instances of Custom Code applied to a Site or Pages. Access to this endpoint requires a bearer token from a Data Client App. Required scope | `custom_code:read`
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
- Parameters:
- - site_id: str. Unique identifier for a Site
+ limit : typing.Optional[int]
+ 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.
- - limit: typing.Optional[float]. Maximum number of records to be returned (max limit: 100)
+ Returns
+ -------
+ ListCustomCodeBlocks
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.sites.scripts.list_custom_code_blocks(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
+ offset=1,
+ limit=1,
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/custom_code/blocks"
- ),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "offset": offset,
- "limit": limit,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = self._raw_client.list_custom_code_blocks(
+ site_id, offset=offset, limit=limit, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(ListCustomCodeBlocks, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
class AsyncScriptsClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = AsyncRawScriptsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawScriptsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawScriptsClient
+ """
+ return self._raw_client
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. Access to this endpoint requires a bearer token from a Data Client App. Required scope | `custom_code:read`
+ 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`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ScriptApplyList
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.sites.scripts.get_custom_code(
- site_id="site_id",
- )
+
+
+ async def main() -> None:
+ await client.sites.scripts.get_custom_code(
+ site_id="580e63e98c9a982ac9b8b741",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/custom_code"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(ScriptApplyList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.get_custom_code(site_id, request_options=request_options)
+ return _response.data
async def upsert_custom_code(
- self, site_id: str, *, request: ScriptApplyList, request_options: typing.Optional[RequestOptions] = None
+ self,
+ site_id: str,
+ *,
+ scripts: typing.Optional[typing.Sequence[ScriptApply]] = OMIT,
+ last_updated: typing.Optional[str] = OMIT,
+ created_on: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
) -> ScriptApplyList:
"""
- 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. Required scope | `custom_code:write`
+ Apply registered scripts to a site. If you have multiple scripts your App needs to apply or maintain on a site, ensure they are always included in the request body for this endpoint. To remove individual scripts, simply call this endpoint without the script in the request body.
- Parameters:
- - site_id: str. Unique identifier for 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.
+
- - request: ScriptApplyList.
+ Required scope | `custom_code:write`
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow import ScriptApply, ScriptApplyList, ScriptApplyLocation
- from webflow.client import AsyncWebflow
+ 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.
+
+ Returns
+ -------
+ ScriptApplyList
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow, ScriptApply
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.sites.scripts.upsert_custom_code(
- site_id="site_id",
- request=ScriptApplyList(
+
+
+ async def main() -> None:
+ await client.sites.scripts.upsert_custom_code(
+ site_id="580e63e98c9a982ac9b8b741",
scripts=[
ScriptApply(
id="cms_slider",
- location=ScriptApplyLocation.HEADER,
+ location="header",
version="1.0.0",
attributes={"my-attribute": "some-value"},
),
ScriptApply(
id="alert",
- location=ScriptApplyLocation.HEADER,
+ location="header",
version="0.0.1",
),
- ScriptApply(
- id="id",
- location=ScriptApplyLocation.HEADER,
- version="version",
- ),
],
- ),
- )
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "PUT",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/custom_code"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.upsert_custom_code(
+ site_id, scripts=scripts, last_updated=last_updated, created_on=created_on, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(ScriptApplyList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
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. Required scope | `custom_code:write`
+ Remove all scripts from a site applied by the App. This endpoint will not remove scripts from the site's registered scripts.
+
+ To remove individual scripts applied by the App, use the [Add/Update Custom Code](/data/reference/custom-code/custom-code-sites/upsert-custom-code) endpoint.
+
+ Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app).
+
+ Required scope | `custom_code:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Returns
+ -------
+ None
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.sites.scripts.delete_custom_code(
- site_id="site_id",
- )
+
+
+ async def main() -> None:
+ await client.sites.scripts.delete_custom_code(
+ site_id="580e63e98c9a982ac9b8b741",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "DELETE",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/custom_code"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.delete_custom_code(site_id, request_options=request_options)
+ return _response.data
async def list_custom_code_blocks(
self,
site_id: str,
*,
- offset: typing.Optional[float] = None,
- limit: typing.Optional[float] = None,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> ListCustomCodeBlocks:
"""
- Get all instances of Custom Code applied to a Site or Pages. Access to this endpoint requires a bearer token from a Data Client App. Required scope | `custom_code:read`
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
- Parameters:
- - site_id: str. Unique identifier for a Site
+ limit : typing.Optional[int]
+ 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.
- - limit: typing.Optional[float]. Maximum number of records to be returned (max limit: 100)
+ Returns
+ -------
+ ListCustomCodeBlocks
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.sites.scripts.list_custom_code_blocks(
- site_id="site_id",
- )
+
+
+ async def main() -> None:
+ await client.sites.scripts.list_custom_code_blocks(
+ site_id="580e63e98c9a982ac9b8b741",
+ offset=1,
+ limit=1,
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/custom_code/blocks"
- ),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "offset": offset,
- "limit": limit,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.list_custom_code_blocks(
+ site_id, offset=offset, limit=limit, request_options=request_options
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(ListCustomCodeBlocks, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
diff --git a/src/webflow/resources/sites/resources/scripts/raw_client.py b/src/webflow/resources/sites/resources/scripts/raw_client.py
new file mode 100644
index 0000000..a5e6bb6
--- /dev/null
+++ b/src/webflow/resources/sites/resources/scripts/raw_client.py
@@ -0,0 +1,946 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from .....core.api_error import ApiError
+from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .....core.http_response import AsyncHttpResponse, HttpResponse
+from .....core.jsonable_encoder import jsonable_encoder
+from .....core.parse_error import ParsingError
+from .....core.pydantic_utilities import parse_obj_as
+from .....core.request_options import RequestOptions
+from .....core.serialization import convert_and_respect_annotation_metadata
+from .....errors.bad_request_error import BadRequestError
+from .....errors.internal_server_error import InternalServerError
+from .....errors.not_found_error import NotFoundError
+from .....errors.too_many_requests_error import TooManyRequestsError
+from .....errors.unauthorized_error import UnauthorizedError
+from .....types.error import Error
+from .....types.list_custom_code_blocks import ListCustomCodeBlocks
+from .....types.script_apply import ScriptApply
+from .....types.script_apply_list import ScriptApplyList
+from pydantic import ValidationError
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RawScriptsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def get_custom_code(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[ScriptApplyList]:
+ """
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[ScriptApplyList]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ScriptApplyList,
+ parse_obj_as(
+ type_=ScriptApplyList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def upsert_custom_code(
+ self,
+ site_id: str,
+ *,
+ scripts: typing.Optional[typing.Sequence[ScriptApply]] = OMIT,
+ last_updated: typing.Optional[str] = OMIT,
+ created_on: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[ScriptApplyList]:
+ """
+ Apply registered scripts to a site. If you have multiple scripts your App needs to apply or maintain on a site, ensure they are always included in the request body for this endpoint. To remove individual scripts, simply call this endpoint without the script in the request body.
+
+
+ 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`
+
+ 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.
+
+ Returns
+ -------
+ HttpResponse[ScriptApplyList]
+ Request was successful
+ """
+ _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(
+ object_=scripts, annotation=typing.Sequence[ScriptApply], direction="write"
+ ),
+ "lastUpdated": last_updated,
+ "createdOn": created_on,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ScriptApplyList,
+ parse_obj_as(
+ type_=ScriptApplyList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def delete_custom_code(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[None]:
+ """
+ Remove all scripts from a site applied by the App. This endpoint will not remove scripts from the site's registered scripts.
+
+ To remove individual scripts applied by the App, use the [Add/Update Custom Code](/data/reference/custom-code/custom-code-sites/upsert-custom-code) endpoint.
+
+ Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app).
+
+ Required scope | `custom_code:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[None]
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"sites/{jsonable_encoder(site_id)}/custom_code",
+ base_url=self._client_wrapper.get_environment().base,
+ method="DELETE",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return HttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def list_custom_code_blocks(
+ self,
+ site_id: str,
+ *,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[ListCustomCodeBlocks]:
+ """
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[ListCustomCodeBlocks]
+ Request was successful
+ """
+ _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,
+ "limit": limit,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ListCustomCodeBlocks,
+ parse_obj_as(
+ type_=ListCustomCodeBlocks, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawScriptsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def get_custom_code(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[ScriptApplyList]:
+ """
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[ScriptApplyList]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ScriptApplyList,
+ parse_obj_as(
+ type_=ScriptApplyList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def upsert_custom_code(
+ self,
+ site_id: str,
+ *,
+ scripts: typing.Optional[typing.Sequence[ScriptApply]] = OMIT,
+ last_updated: typing.Optional[str] = OMIT,
+ created_on: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[ScriptApplyList]:
+ """
+ Apply registered scripts to a site. If you have multiple scripts your App needs to apply or maintain on a site, ensure they are always included in the request body for this endpoint. To remove individual scripts, simply call this endpoint without the script in the request body.
+
+
+ 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`
+
+ 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.
+
+ Returns
+ -------
+ AsyncHttpResponse[ScriptApplyList]
+ Request was successful
+ """
+ _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(
+ object_=scripts, annotation=typing.Sequence[ScriptApply], direction="write"
+ ),
+ "lastUpdated": last_updated,
+ "createdOn": created_on,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ScriptApplyList,
+ parse_obj_as(
+ type_=ScriptApplyList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def delete_custom_code(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[None]:
+ """
+ Remove all scripts from a site applied by the App. This endpoint will not remove scripts from the site's registered scripts.
+
+ To remove individual scripts applied by the App, use the [Add/Update Custom Code](/data/reference/custom-code/custom-code-sites/upsert-custom-code) endpoint.
+
+ Access to this endpoint requires a bearer token obtained from an [OAuth Code Grant Flow](/data/reference/oauth-app).
+
+ Required scope | `custom_code:write`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[None]
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"sites/{jsonable_encoder(site_id)}/custom_code",
+ base_url=self._client_wrapper.get_environment().base,
+ method="DELETE",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return AsyncHttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def list_custom_code_blocks(
+ self,
+ site_id: str,
+ *,
+ offset: typing.Optional[int] = None,
+ limit: typing.Optional[int] = None,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[ListCustomCodeBlocks]:
+ """
+ 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`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ limit : typing.Optional[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[ListCustomCodeBlocks]
+ Request was successful
+ """
+ _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,
+ "limit": limit,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ListCustomCodeBlocks,
+ parse_obj_as(
+ type_=ListCustomCodeBlocks, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/sites/resources/well_known/__init__.py b/src/webflow/resources/sites/resources/well_known/__init__.py
new file mode 100644
index 0000000..34fc810
--- /dev/null
+++ b/src/webflow/resources/sites/resources/well_known/__init__.py
@@ -0,0 +1,34 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .types import WellKnownFileContentType
+_dynamic_imports: typing.Dict[str, str] = {"WellKnownFileContentType": ".types"}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = ["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..14c76ae
--- /dev/null
+++ b/src/webflow/resources/sites/resources/well_known/client.py
@@ -0,0 +1,283 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .....core.request_options import RequestOptions
+from .raw_client import AsyncRawWellKnownClient, RawWellKnownClient
+from .types.well_known_file_content_type import WellKnownFileContentType
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class WellKnownClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._raw_client = RawWellKnownClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawWellKnownClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawWellKnownClient
+ """
+ return self._raw_client
+
+ 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="apple-app-site-association.txt",
+ file_data='{\n "applinks": {\n "apps": [],\n "details": [\n {\n "appID": "ABCDE12345.com.example.app",\n "paths": [ "/*", "/some/path/*" ]\n }\n ]\n }\n}\n',
+ content_type="application/json",
+ )
+ """
+ _response = self._raw_client.put(
+ site_id,
+ file_name=file_name,
+ file_data=file_data,
+ content_type=content_type,
+ request_options=request_options,
+ )
+ return _response.data
+
+ 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._raw_client.delete(site_id, file_names=file_names, request_options=request_options)
+ return _response.data
+
+
+class AsyncWellKnownClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._raw_client = AsyncRawWellKnownClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawWellKnownClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawWellKnownClient
+ """
+ return self._raw_client
+
+ 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="apple-app-site-association.txt",
+ file_data='{\n "applinks": {\n "apps": [],\n "details": [\n {\n "appID": "ABCDE12345.com.example.app",\n "paths": [ "/*", "/some/path/*" ]\n }\n ]\n }\n}\n',
+ content_type="application/json",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.put(
+ site_id,
+ file_name=file_name,
+ file_data=file_data,
+ content_type=content_type,
+ request_options=request_options,
+ )
+ return _response.data
+
+ 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._raw_client.delete(site_id, file_names=file_names, request_options=request_options)
+ return _response.data
diff --git a/src/webflow/resources/sites/resources/well_known/raw_client.py b/src/webflow/resources/sites/resources/well_known/raw_client.py
new file mode 100644
index 0000000..7125705
--- /dev/null
+++ b/src/webflow/resources/sites/resources/well_known/raw_client.py
@@ -0,0 +1,507 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from .....core.api_error import ApiError
+from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .....core.http_response import AsyncHttpResponse, HttpResponse
+from .....core.jsonable_encoder import jsonable_encoder
+from .....core.parse_error import ParsingError
+from .....core.pydantic_utilities import parse_obj_as
+from .....core.request_options import RequestOptions
+from .....errors.bad_request_error import BadRequestError
+from .....errors.internal_server_error import InternalServerError
+from .....errors.not_found_error import NotFoundError
+from .....errors.too_many_requests_error import TooManyRequestsError
+from .....errors.unauthorized_error import UnauthorizedError
+from .....types.error import Error
+from .types.well_known_file_content_type import WellKnownFileContentType
+from pydantic import ValidationError
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RawWellKnownClient:
+ 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,
+ ) -> HttpResponse[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
+ -------
+ HttpResponse[None]
+ """
+ _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 HttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def delete(
+ self,
+ site_id: str,
+ *,
+ file_names: typing.Optional[typing.Sequence[str]] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[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
+ -------
+ HttpResponse[None]
+ """
+ _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 HttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawWellKnownClient:
+ 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,
+ ) -> AsyncHttpResponse[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
+ -------
+ AsyncHttpResponse[None]
+ """
+ _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 AsyncHttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def delete(
+ self,
+ site_id: str,
+ *,
+ file_names: typing.Optional[typing.Sequence[str]] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[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
+ -------
+ AsyncHttpResponse[None]
+ """
+ _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 AsyncHttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
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..a5ec3aa
--- /dev/null
+++ b/src/webflow/resources/sites/resources/well_known/types/__init__.py
@@ -0,0 +1,34 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .well_known_file_content_type import WellKnownFileContentType
+_dynamic_imports: typing.Dict[str, str] = {"WellKnownFileContentType": ".well_known_file_content_type"}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = ["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/sites/types/__init__.py b/src/webflow/resources/sites/types/__init__.py
new file mode 100644
index 0000000..960aec6
--- /dev/null
+++ b/src/webflow/resources/sites/types/__init__.py
@@ -0,0 +1,34 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .sites_publish_response import SitesPublishResponse
+_dynamic_imports: typing.Dict[str, str] = {"SitesPublishResponse": ".sites_publish_response"}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = ["SitesPublishResponse"]
diff --git a/src/webflow/resources/sites/types/sites_publish_response.py b/src/webflow/resources/sites/types/sites_publish_response.py
new file mode 100644
index 0000000..d32e70c
--- /dev/null
+++ b/src/webflow/resources/sites/types/sites_publish_response.py
@@ -0,0 +1,31 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ....core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ....core.serialization import FieldMetadata
+from ....types.domain import Domain
+
+
+class SitesPublishResponse(UniversalBaseModel):
+ custom_domains: typing_extensions.Annotated[
+ typing.Optional[typing.List[Domain]],
+ FieldMetadata(alias="customDomains"),
+ pydantic.Field(alias="customDomains", description="Array of domains objects"),
+ ] = None
+ publish_to_webflow_subdomain: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="publishToWebflowSubdomain"),
+ pydantic.Field(alias="publishToWebflowSubdomain", description="Flag for publishing to webflow.io subdomain"),
+ ] = 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/token/__init__.py b/src/webflow/resources/token/__init__.py
index f3ea265..5cde020 100644
--- a/src/webflow/resources/token/__init__.py
+++ b/src/webflow/resources/token/__init__.py
@@ -1,2 +1,4 @@
# This file was auto-generated by Fern from our API Definition.
+# isort: skip_file
+
diff --git a/src/webflow/resources/token/client.py b/src/webflow/resources/token/client.py
index 9236d46..d4712d7 100644
--- a/src/webflow/resources/token/client.py
+++ b/src/webflow/resources/token/client.py
@@ -1,202 +1,169 @@
# This file was auto-generated by Fern from our API Definition.
import typing
-import urllib.parse
-from json.decoder import JSONDecodeError
-from ...core.api_error import ApiError
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from ...core.jsonable_encoder import jsonable_encoder
-from ...core.remove_none_from_dict import remove_none_from_dict
from ...core.request_options import RequestOptions
-from ...errors.forbidden_error import ForbiddenError
-from ...errors.unauthorized_error import UnauthorizedError
from ...types.authorization import Authorization
from ...types.authorized_user import AuthorizedUser
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+from .raw_client import AsyncRawTokenClient, RawTokenClient
class TokenClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = RawTokenClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawTokenClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawTokenClient
+ """
+ return self._raw_client
def authorized_by(self, *, request_options: typing.Optional[RequestOptions] = None) -> AuthorizedUser:
"""
- Information about the Authorized User Required Scope | `authorized_user:read`
+ Information about the Authorized User
- Parameters:
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Required Scope | `authorized_user:read`
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AuthorizedUser
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.token.authorized_by()
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "token/authorized_by"),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(AuthorizedUser, _response.json()) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.authorized_by(request_options=request_options)
+ return _response.data
def introspect(self, *, request_options: typing.Optional[RequestOptions] = None) -> Authorization:
"""
- Information about the authorization token Access to this endpoint requires a bearer token from a Data Client App.
+ Information about the authorization token
- Parameters:
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients).
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Authorization
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.token.introspect()
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "token/introspect"),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Authorization, _response.json()) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.introspect(request_options=request_options)
+ return _response.data
class AsyncTokenClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = AsyncRawTokenClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawTokenClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawTokenClient
+ """
+ return self._raw_client
async def authorized_by(self, *, request_options: typing.Optional[RequestOptions] = None) -> AuthorizedUser:
"""
- Information about the Authorized User Required Scope | `authorized_user:read`
+ Information about the Authorized User
+
+ Required Scope | `authorized_user:read`
- Parameters:
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AuthorizedUser
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.token.authorized_by()
+
+
+ async def main() -> None:
+ await client.token.authorized_by()
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "token/authorized_by"),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(AuthorizedUser, _response.json()) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.authorized_by(request_options=request_options)
+ return _response.data
async def introspect(self, *, request_options: typing.Optional[RequestOptions] = None) -> Authorization:
"""
- Information about the authorization token Access to this endpoint requires a bearer token from a Data Client App.
+ Information about the authorization token
+
+ Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients).
- Parameters:
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Authorization
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.token.introspect()
+
+
+ async def main() -> None:
+ await client.token.introspect()
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "token/introspect"),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Authorization, _response.json()) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.introspect(request_options=request_options)
+ return _response.data
diff --git a/src/webflow/resources/token/raw_client.py b/src/webflow/resources/token/raw_client.py
new file mode 100644
index 0000000..ea49a25
--- /dev/null
+++ b/src/webflow/resources/token/raw_client.py
@@ -0,0 +1,261 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from json.decoder import JSONDecodeError
+
+from ...core.api_error import ApiError
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.http_response import AsyncHttpResponse, HttpResponse
+from ...core.parse_error import ParsingError
+from ...core.pydantic_utilities import parse_obj_as
+from ...core.request_options import RequestOptions
+from ...errors.forbidden_error import ForbiddenError
+from ...errors.unauthorized_error import UnauthorizedError
+from ...types.authorization import Authorization
+from ...types.authorized_user import AuthorizedUser
+from ...types.error import Error
+from pydantic import ValidationError
+
+
+class RawTokenClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def authorized_by(self, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[AuthorizedUser]:
+ """
+ Information about the Authorized User
+
+ Required Scope | `authorized_user:read`
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[AuthorizedUser]
+ Request was successful
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ "token/authorized_by",
+ base_url=self._client_wrapper.get_environment().base,
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ AuthorizedUser,
+ parse_obj_as(
+ type_=AuthorizedUser, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def introspect(self, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[Authorization]:
+ """
+ Information about the authorization token
+
+ Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients).
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Authorization]
+ Request was successful
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ "token/introspect",
+ base_url=self._client_wrapper.get_environment().base,
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Authorization,
+ parse_obj_as(
+ type_=Authorization, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawTokenClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def authorized_by(
+ self, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[AuthorizedUser]:
+ """
+ Information about the Authorized User
+
+ Required Scope | `authorized_user:read`
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[AuthorizedUser]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ AuthorizedUser,
+ parse_obj_as(
+ type_=AuthorizedUser, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def introspect(
+ self, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[Authorization]:
+ """
+ Information about the authorization token
+
+ Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients).
+
+ Parameters
+ ----------
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Authorization]
+ Request was successful
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ "token/introspect",
+ base_url=self._client_wrapper.get_environment().base,
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Authorization,
+ parse_obj_as(
+ type_=Authorization, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/users/__init__.py b/src/webflow/resources/users/__init__.py
deleted file mode 100644
index 88e72a2..0000000
--- a/src/webflow/resources/users/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .types import UsersListRequestSort, UsersUpdateRequestData
-
-__all__ = ["UsersListRequestSort", "UsersUpdateRequestData"]
diff --git a/src/webflow/resources/users/client.py b/src/webflow/resources/users/client.py
deleted file mode 100644
index f3d62bf..0000000
--- a/src/webflow/resources/users/client.py
+++ /dev/null
@@ -1,810 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-import urllib.parse
-from json.decoder import JSONDecodeError
-
-from ...core.api_error import ApiError
-from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from ...core.jsonable_encoder import jsonable_encoder
-from ...core.remove_none_from_dict import remove_none_from_dict
-from ...core.request_options import RequestOptions
-from ...errors.bad_request_error import BadRequestError
-from ...errors.conflict_error import ConflictError
-from ...errors.forbidden_error import ForbiddenError
-from ...errors.internal_server_error import InternalServerError
-from ...errors.not_found_error import NotFoundError
-from ...errors.too_many_requests_error import TooManyRequestsError
-from ...errors.unauthorized_error import UnauthorizedError
-from ...types.user import User
-from ...types.user_list import UserList
-from .types.users_list_request_sort import UsersListRequestSort
-from .types.users_update_request_data import UsersUpdateRequestData
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-# this is used as the default value for optional parameters
-OMIT = typing.cast(typing.Any, ...)
-
-
-class UsersClient:
- def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
-
- def list(
- self,
- site_id: str,
- *,
- offset: typing.Optional[float] = None,
- limit: typing.Optional[float] = None,
- sort: typing.Optional[UsersListRequestSort] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> UserList:
- """
- Get a list of users for a site Required scope | `users:read`
-
- 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)
-
- - 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`)
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
-
- client = Webflow(
- access_token="YOUR_ACCESS_TOKEN",
- )
- client.users.list(
- site_id="site_id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/users"),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "offset": offset,
- "limit": limit,
- "sort": sort,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(UserList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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(self, site_id: str, user_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> User:
- """
- Get a User by ID Required scope | `users:read`
-
- Parameters:
- - site_id: str. Unique identifier for a Site
-
- - user_id: str. Unique identifier for a User
-
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
-
- client = Webflow(
- access_token="YOUR_ACCESS_TOKEN",
- )
- client.users.get(
- site_id="site_id",
- user_id="user_id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/users/{jsonable_encoder(user_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(User, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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, user_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
- """
- Delete a User by ID Required scope | `users:write`
-
- Parameters:
- - site_id: str. Unique identifier for a Site
-
- - user_id: str. Unique identifier for a User
-
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
-
- client = Webflow(
- access_token="YOUR_ACCESS_TOKEN",
- )
- client.users.delete(
- site_id="site_id",
- user_id="user_id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- "DELETE",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/users/{jsonable_encoder(user_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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(
- self,
- site_id: str,
- user_id: str,
- *,
- data: typing.Optional[UsersUpdateRequestData] = OMIT,
- access_groups: typing.Optional[typing.Sequence[str]] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> User:
- """
- Update a User by ID Required scope | `users:write`
-
- The email and password fields cannot be updated using this endpoint
-
- Parameters:
- - site_id: str. Unique identifier for a Site
-
- - 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.
-
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow import UsersUpdateRequestData
- from webflow.client import Webflow
-
- client = Webflow(
- access_token="YOUR_ACCESS_TOKEN",
- )
- client.users.update(
- site_id="site_id",
- user_id="user_id",
- data=UsersUpdateRequestData(
- name="Some One",
- accept_privacy=False,
- accept_communications=False,
- ),
- access_groups=["webflowers", "platinum", "free-tier", "accessGroups"],
- )
- """
- _request: typing.Dict[str, typing.Any] = {}
- if data is not OMIT:
- _request["data"] = data
- if access_groups is not OMIT:
- _request["accessGroups"] = access_groups
- _response = self._client_wrapper.httpx_client.request(
- "PATCH",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/users/{jsonable_encoder(user_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(User, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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 invite(
- self,
- site_id: str,
- *,
- email: str,
- access_groups: typing.Optional[typing.Sequence[str]] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> User:
- """
- 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 Access Groups. Required scope | `users:write`
-
- Parameters:
- - site_id: str. Unique identifier for a Site
-
- - 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.
-
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
-
- client = Webflow(
- access_token="YOUR_ACCESS_TOKEN",
- )
- client.users.invite(
- site_id="site_id",
- email="some.one@home.com",
- access_groups=["webflowers", "accessGroups"],
- )
- """
- _request: typing.Dict[str, typing.Any] = {"email": email}
- if access_groups is not OMIT:
- _request["accessGroups"] = access_groups
- _response = self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/users/invite"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(User, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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 AsyncUsersClient:
- def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
-
- async def list(
- self,
- site_id: str,
- *,
- offset: typing.Optional[float] = None,
- limit: typing.Optional[float] = None,
- sort: typing.Optional[UsersListRequestSort] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> UserList:
- """
- Get a list of users for a site Required scope | `users:read`
-
- 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)
-
- - 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`)
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
-
- client = AsyncWebflow(
- access_token="YOUR_ACCESS_TOKEN",
- )
- await client.users.list(
- site_id="site_id",
- )
- """
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/users"),
- params=jsonable_encoder(
- remove_none_from_dict(
- {
- "offset": offset,
- "limit": limit,
- "sort": sort,
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- }
- )
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(UserList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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(self, site_id: str, user_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> User:
- """
- Get a User by ID Required scope | `users:read`
-
- Parameters:
- - site_id: str. Unique identifier for a Site
-
- - user_id: str. Unique identifier for a User
-
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
-
- client = AsyncWebflow(
- access_token="YOUR_ACCESS_TOKEN",
- )
- await client.users.get(
- site_id="site_id",
- user_id="user_id",
- )
- """
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/users/{jsonable_encoder(user_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(User, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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, user_id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> None:
- """
- Delete a User by ID Required scope | `users:write`
-
- Parameters:
- - site_id: str. Unique identifier for a Site
-
- - user_id: str. Unique identifier for a User
-
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
-
- client = AsyncWebflow(
- access_token="YOUR_ACCESS_TOKEN",
- )
- await client.users.delete(
- site_id="site_id",
- user_id="user_id",
- )
- """
- _response = await self._client_wrapper.httpx_client.request(
- "DELETE",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/users/{jsonable_encoder(user_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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(
- self,
- site_id: str,
- user_id: str,
- *,
- data: typing.Optional[UsersUpdateRequestData] = OMIT,
- access_groups: typing.Optional[typing.Sequence[str]] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> User:
- """
- Update a User by ID Required scope | `users:write`
-
- The email and password fields cannot be updated using this endpoint
-
- Parameters:
- - site_id: str. Unique identifier for a Site
-
- - 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.
-
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow import UsersUpdateRequestData
- from webflow.client import AsyncWebflow
-
- client = AsyncWebflow(
- access_token="YOUR_ACCESS_TOKEN",
- )
- await client.users.update(
- site_id="site_id",
- user_id="user_id",
- data=UsersUpdateRequestData(
- name="Some One",
- accept_privacy=False,
- accept_communications=False,
- ),
- access_groups=["webflowers", "platinum", "free-tier", "accessGroups"],
- )
- """
- _request: typing.Dict[str, typing.Any] = {}
- if data is not OMIT:
- _request["data"] = data
- if access_groups is not OMIT:
- _request["accessGroups"] = access_groups
- _response = await self._client_wrapper.httpx_client.request(
- "PATCH",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/",
- f"sites/{jsonable_encoder(site_id)}/users/{jsonable_encoder(user_id)}",
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(User, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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 invite(
- self,
- site_id: str,
- *,
- email: str,
- access_groups: typing.Optional[typing.Sequence[str]] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> User:
- """
- 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 Access Groups. Required scope | `users:write`
-
- Parameters:
- - site_id: str. Unique identifier for a Site
-
- - 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.
-
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
-
- client = AsyncWebflow(
- access_token="YOUR_ACCESS_TOKEN",
- )
- await client.users.invite(
- site_id="site_id",
- email="some.one@home.com",
- access_groups=["webflowers", "accessGroups"],
- )
- """
- _request: typing.Dict[str, typing.Any] = {"email": email}
- if access_groups is not OMIT:
- _request["accessGroups"] = access_groups
- _response = await self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/users/invite"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(User, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 403:
- raise ForbiddenError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 409:
- raise ConflictError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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/users/types/__init__.py b/src/webflow/resources/users/types/__init__.py
deleted file mode 100644
index cadf367..0000000
--- a/src/webflow/resources/users/types/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-# 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"]
diff --git a/src/webflow/resources/users/types/users_list_request_sort.py b/src/webflow/resources/users/types/users_list_request_sort.py
deleted file mode 100644
index abd1e99..0000000
--- a/src/webflow/resources/users/types/users_list_request_sort.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import enum
-import typing
-
-T_Result = typing.TypeVar("T_Result")
-
-
-class UsersListRequestSort(str, enum.Enum):
- CREATED_ON_ASCENDING = "CreatedOn"
- """
- Sorts users in ascending order based on their created date
- """
-
- CREATED_ON_DESCENDING = "-CreatedOn"
- """
- Sorts users in descending order based on their created date
- """
-
- EMAIL_ASCENDING = "Email"
- """
- Sorts users in ascending order based on their email
- """
-
- EMAIL_DESCENDING = "-Email"
- """
- Sorts users in descending order based on their email
- """
-
- STATUS_ASCENDING = "Status"
- """
- Sorts users in ascending order based on their status
- """
-
- STATUS_DESCENDING = "-Status"
- """
- Sorts users in descending order based on their status
- """
-
- LAST_LOGIN_ASCENDING = "LastLogin"
- """
- Sorts users in ascending order based on their last login date
- """
-
- LAST_LOGIN_DESCENDING = "-LastLogin"
- """
- Sorts users in descending order based on their last login date
- """
-
- UPDATED_ON_ASCENDING = "UpdatedOn"
- """
- Sorts users in ascending order based on their update date
- """
-
- UPDATED_ON_DESCENDING = "-UpdatedOn"
- """
- Sorts users in descending order based on their update date
- """
-
- def visit(
- self,
- created_on_ascending: typing.Callable[[], T_Result],
- created_on_descending: typing.Callable[[], T_Result],
- email_ascending: typing.Callable[[], T_Result],
- email_descending: typing.Callable[[], T_Result],
- status_ascending: typing.Callable[[], T_Result],
- status_descending: typing.Callable[[], T_Result],
- last_login_ascending: typing.Callable[[], T_Result],
- last_login_descending: typing.Callable[[], T_Result],
- updated_on_ascending: typing.Callable[[], T_Result],
- updated_on_descending: typing.Callable[[], T_Result],
- ) -> T_Result:
- if self is UsersListRequestSort.CREATED_ON_ASCENDING:
- return created_on_ascending()
- if self is UsersListRequestSort.CREATED_ON_DESCENDING:
- return created_on_descending()
- if self is UsersListRequestSort.EMAIL_ASCENDING:
- return email_ascending()
- if self is UsersListRequestSort.EMAIL_DESCENDING:
- return email_descending()
- if self is UsersListRequestSort.STATUS_ASCENDING:
- return status_ascending()
- if self is UsersListRequestSort.STATUS_DESCENDING:
- return status_descending()
- if self is UsersListRequestSort.LAST_LOGIN_ASCENDING:
- return last_login_ascending()
- if self is UsersListRequestSort.LAST_LOGIN_DESCENDING:
- return last_login_descending()
- if self is UsersListRequestSort.UPDATED_ON_ASCENDING:
- return updated_on_ascending()
- if self is UsersListRequestSort.UPDATED_ON_DESCENDING:
- return updated_on_descending()
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 cb99ef6..0000000
--- a/src/webflow/resources/users/types/users_update_request_data.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import datetime as dt
-import typing
-
-from ....core.datetime_utils import serialize_datetime
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class UsersUpdateRequestData(pydantic.BaseModel):
- name: typing.Optional[str] = pydantic.Field(default=None, description="The name of the user")
- accept_privacy: typing.Optional[bool] = pydantic.Field(
- alias="accept-privacy",
- default=None,
- description="Boolean indicating if the user has accepted the privacy policy",
- )
- accept_communications: typing.Optional[bool] = pydantic.Field(
- alias="accept-communications",
- default=None,
- description="Boolean indicating if the user has accepted to receive communications",
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
diff --git a/src/webflow/resources/webhooks/__init__.py b/src/webflow/resources/webhooks/__init__.py
index f3ea265..5cde020 100644
--- a/src/webflow/resources/webhooks/__init__.py
+++ b/src/webflow/resources/webhooks/__init__.py
@@ -1,2 +1,4 @@
# This file was auto-generated by Fern from our API Definition.
+# isort: skip_file
+
diff --git a/src/webflow/resources/webhooks/client.py b/src/webflow/resources/webhooks/client.py
index 0309b13..4360526 100644
--- a/src/webflow/resources/webhooks/client.py
+++ b/src/webflow/resources/webhooks/client.py
@@ -1,27 +1,15 @@
# This file was auto-generated by Fern from our API Definition.
+import datetime as dt
import typing
-import urllib.parse
-from json.decoder import JSONDecodeError
-from ...core.api_error import ApiError
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from ...core.jsonable_encoder import jsonable_encoder
-from ...core.remove_none_from_dict import remove_none_from_dict
from ...core.request_options import RequestOptions
-from ...errors.bad_request_error import BadRequestError
-from ...errors.internal_server_error import InternalServerError
-from ...errors.not_found_error import NotFoundError
-from ...errors.too_many_requests_error import TooManyRequestsError
-from ...errors.unauthorized_error import UnauthorizedError
from ...types.trigger_type import TriggerType
from ...types.webhook import Webhook
+from ...types.webhook_filter import WebhookFilter
from ...types.webhook_list import WebhookList
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+from .raw_client import AsyncRawWebhooksClient, RawWebhooksClient
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
@@ -29,503 +17,450 @@
class WebhooksClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = RawWebhooksClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawWebhooksClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawWebhooksClient
+ """
+ return self._raw_client
def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> WebhookList:
"""
- List all App-created Webhooks registered for a given site Required scope | `sites:read`
+ List all App-created Webhooks registered for a given site
+
+ Required scope | `sites:read`
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ WebhookList
+ Request was successful
+
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.webhooks.list(
- site_id="site_id",
+ site_id="580e63e98c9a982ac9b8b741",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/webhooks"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(WebhookList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.list(site_id, request_options=request_options)
+ return _response.data
def create(
self,
- site_id: str,
+ site_id_: str,
*,
- trigger_type: TriggerType,
- url: str,
- filter: typing.Optional[typing.Dict[str, typing.Any]] = OMIT,
+ id: typing.Optional[str] = OMIT,
+ trigger_type: typing.Optional[TriggerType] = OMIT,
+ url: typing.Optional[str] = OMIT,
+ workspace_id: typing.Optional[str] = OMIT,
+ site_id: typing.Optional[str] = OMIT,
+ filter: typing.Optional[WebhookFilter] = OMIT,
+ last_triggered: typing.Optional[dt.datetime] = OMIT,
+ created_on: typing.Optional[dt.datetime] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
) -> Webhook:
"""
- Create a new Webhook, to be notified when Webflow resources change. Limit of 75 registrations per `triggerType`, per site. Access to this endpoint requires a bearer token from a Data Client App. The only exceptions are for creating webhooks with `site_publish` or `form_submission` triggers, which can be done with Site Tokens Required scope | `sites:write`
+ Create a new Webhook.
- Parameters:
- - site_id: str. Unique identifier for a Site
+ Limit of 75 registrations per `triggerType`, per site.
- - trigger_type: TriggerType.
+ Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients).
+ Required scope | `sites:write`
- - url: str. The server URI that Webflow will call when your Webhook is triggered
+ Parameters
+ ----------
+ site_id_ : str
+ Unique identifier for a Site
- - filter: typing.Optional[typing.Dict[str, typing.Any]]. Filter for selecting which events you want Webhooks to be triggered for.
- ** Only available for `form_submission` trigger types. **
+ id : typing.Optional[str]
+ Unique identifier for the Webhook registration
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow import TriggerType
- from webflow.client import Webflow
+ trigger_type : typing.Optional[TriggerType]
+
+ url : typing.Optional[str]
+ URL to send the Webhook payload to
+
+ workspace_id : typing.Optional[str]
+ Unique identifier for the Workspace the Webhook is registered in
+
+ site_id : typing.Optional[str]
+ Unique identifier for the Site the Webhook is registered in
+
+ filter : typing.Optional[WebhookFilter]
+ Only supported for the `form_submission` trigger type. Filter for the form you want Webhooks to be sent for.
+
+ last_triggered : typing.Optional[dt.datetime]
+ Date the Webhook instance was last triggered
+
+ created_on : typing.Optional[dt.datetime]
+ Date the Webhook registration was created
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Webhook
+ Request was successful
+
+ Examples
+ --------
+ import datetime
+
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.webhooks.create(
- site_id="site_id",
- trigger_type=TriggerType.FORM_SUBMISSION,
- url="https://api.mydomain.com/webhook",
- )
- """
- _request: typing.Dict[str, typing.Any] = {"triggerType": trigger_type, "url": url}
- if filter is not OMIT:
- _request["filter"] = filter
- _response = self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/webhooks"
+ site_id_="580e63e98c9a982ac9b8b741",
+ id="582266e0cd48de0f0e3c6d8b",
+ trigger_type="form_submission",
+ url="https://webhook.site/7f7f7f7f-7f7f-7f7f-7f7f-7f7f7f7f7f7f",
+ workspace_id="4f4e46fd476ea8c507000001",
+ site_id="562ac0395358780a1f5e6fbd",
+ last_triggered=datetime.datetime.fromisoformat(
+ "2023-02-08 23:59:28+00:00",
),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
+ created_on=datetime.datetime.fromisoformat(
+ "2022-11-08 23:59:28+00:00",
),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Webhook, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ """
+ _response = self._raw_client.create(
+ site_id_,
+ id=id,
+ trigger_type=trigger_type,
+ url=url,
+ workspace_id=workspace_id,
+ site_id=site_id,
+ filter=filter,
+ last_triggered=last_triggered,
+ created_on=created_on,
+ request_options=request_options,
+ )
+ return _response.data
def get(self, webhook_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Webhook:
"""
Get a specific Webhook instance
- Parameters:
- - webhook_id: str. Unique identifier for a Webhook
+ Required scope: `sites:read`
+
+ Parameters
+ ----------
+ webhook_id : str
+ Unique identifier for a Webhook
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Webhook
+ Request was successful
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.webhooks.get(
- webhook_id="webhook_id",
+ webhook_id="580e64008c9a982ac9b8b754",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"webhooks/{jsonable_encoder(webhook_id)}"),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Webhook, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.get(webhook_id, request_options=request_options)
+ return _response.data
def delete(self, webhook_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
"""
Remove a Webhook
- Parameters:
- - webhook_id: str. Unique identifier for a Webhook
+ Required scope: `sites:read`
+
+ Parameters
+ ----------
+ webhook_id : str
+ Unique identifier for a Webhook
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import Webflow
+ Examples
+ --------
+ from webflow import Webflow
client = Webflow(
access_token="YOUR_ACCESS_TOKEN",
)
client.webhooks.delete(
- webhook_id="webhook_id",
+ webhook_id="580e64008c9a982ac9b8b754",
)
"""
- _response = self._client_wrapper.httpx_client.request(
- "DELETE",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"webhooks/{jsonable_encoder(webhook_id)}"),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = self._raw_client.delete(webhook_id, request_options=request_options)
+ return _response.data
class AsyncWebhooksClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
+ self._raw_client = AsyncRawWebhooksClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawWebhooksClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawWebhooksClient
+ """
+ return self._raw_client
async def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> WebhookList:
"""
- List all App-created Webhooks registered for a given site Required scope | `sites:read`
+ List all App-created Webhooks registered for a given site
+
+ Required scope | `sites:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
- Parameters:
- - site_id: str. Unique identifier for a Site
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Returns
+ -------
+ WebhookList
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.webhooks.list(
- site_id="site_id",
- )
+
+
+ async def main() -> None:
+ await client.webhooks.list(
+ site_id="580e63e98c9a982ac9b8b741",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/webhooks"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(WebhookList, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.list(site_id, request_options=request_options)
+ return _response.data
async def create(
self,
- site_id: str,
+ site_id_: str,
*,
- trigger_type: TriggerType,
- url: str,
- filter: typing.Optional[typing.Dict[str, typing.Any]] = OMIT,
+ id: typing.Optional[str] = OMIT,
+ trigger_type: typing.Optional[TriggerType] = OMIT,
+ url: typing.Optional[str] = OMIT,
+ workspace_id: typing.Optional[str] = OMIT,
+ site_id: typing.Optional[str] = OMIT,
+ filter: typing.Optional[WebhookFilter] = OMIT,
+ last_triggered: typing.Optional[dt.datetime] = OMIT,
+ created_on: typing.Optional[dt.datetime] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
) -> Webhook:
"""
- Create a new Webhook, to be notified when Webflow resources change. Limit of 75 registrations per `triggerType`, per site. Access to this endpoint requires a bearer token from a Data Client App. The only exceptions are for creating webhooks with `site_publish` or `form_submission` triggers, which can be done with Site Tokens Required scope | `sites:write`
+ Create a new Webhook.
+
+ Limit of 75 registrations per `triggerType`, per site.
+
+ Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients).
+ Required scope | `sites:write`
+
+ Parameters
+ ----------
+ site_id_ : str
+ Unique identifier for a Site
+
+ id : typing.Optional[str]
+ Unique identifier for the Webhook registration
- Parameters:
- - site_id: str. Unique identifier for a Site
+ trigger_type : typing.Optional[TriggerType]
- - trigger_type: TriggerType.
+ url : typing.Optional[str]
+ URL to send the Webhook payload to
- - url: str. The server URI that Webflow will call when your Webhook is triggered
+ workspace_id : typing.Optional[str]
+ Unique identifier for the Workspace the Webhook is registered in
- - filter: typing.Optional[typing.Dict[str, typing.Any]]. Filter for selecting which events you want Webhooks to be triggered for.
- ** Only available for `form_submission` trigger types. **
+ site_id : typing.Optional[str]
+ Unique identifier for the Site the Webhook is registered in
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow import TriggerType
- from webflow.client import AsyncWebflow
+ filter : typing.Optional[WebhookFilter]
+ Only supported for the `form_submission` trigger type. Filter for the form you want Webhooks to be sent for.
+
+ last_triggered : typing.Optional[dt.datetime]
+ Date the Webhook instance was last triggered
+
+ created_on : typing.Optional[dt.datetime]
+ Date the Webhook registration was created
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Webhook
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+ import datetime
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.webhooks.create(
- site_id="site_id",
- trigger_type=TriggerType.FORM_SUBMISSION,
- url="https://api.mydomain.com/webhook",
- )
+
+
+ async def main() -> None:
+ await client.webhooks.create(
+ site_id_="580e63e98c9a982ac9b8b741",
+ id="582266e0cd48de0f0e3c6d8b",
+ trigger_type="form_submission",
+ url="https://webhook.site/7f7f7f7f-7f7f-7f7f-7f7f-7f7f7f7f7f7f",
+ workspace_id="4f4e46fd476ea8c507000001",
+ site_id="562ac0395358780a1f5e6fbd",
+ last_triggered=datetime.datetime.fromisoformat(
+ "2023-02-08 23:59:28+00:00",
+ ),
+ created_on=datetime.datetime.fromisoformat(
+ "2022-11-08 23:59:28+00:00",
+ ),
+ )
+
+
+ asyncio.run(main())
"""
- _request: typing.Dict[str, typing.Any] = {"triggerType": trigger_type, "url": url}
- if filter is not OMIT:
- _request["filter"] = filter
- _response = await self._client_wrapper.httpx_client.request(
- "POST",
- urllib.parse.urljoin(
- f"{self._client_wrapper.get_base_url()}/", f"sites/{jsonable_encoder(site_id)}/webhooks"
- ),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- json=jsonable_encoder(_request)
- if request_options is None or request_options.get("additional_body_parameters") is None
- else {
- **jsonable_encoder(_request),
- **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
- },
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
+ _response = await self._raw_client.create(
+ site_id_,
+ id=id,
+ trigger_type=trigger_type,
+ url=url,
+ workspace_id=workspace_id,
+ site_id=site_id,
+ filter=filter,
+ last_triggered=last_triggered,
+ created_on=created_on,
+ request_options=request_options,
)
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Webhook, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ return _response.data
async def get(self, webhook_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Webhook:
"""
Get a specific Webhook instance
- Parameters:
- - webhook_id: str. Unique identifier for a Webhook
+ Required scope: `sites:read`
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Parameters
+ ----------
+ webhook_id : str
+ Unique identifier for a Webhook
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ Webhook
+ Request was successful
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.webhooks.get(
- webhook_id="webhook_id",
- )
+
+
+ async def main() -> None:
+ await client.webhooks.get(
+ webhook_id="580e64008c9a982ac9b8b754",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "GET",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"webhooks/{jsonable_encoder(webhook_id)}"),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return pydantic.parse_obj_as(Webhook, _response.json()) # type: ignore
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.get(webhook_id, request_options=request_options)
+ return _response.data
async def delete(self, webhook_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
"""
Remove a Webhook
- Parameters:
- - webhook_id: str. Unique identifier for a Webhook
+ Required scope: `sites:read`
- - request_options: typing.Optional[RequestOptions]. Request-specific configuration.
- ---
- from webflow.client import AsyncWebflow
+ Parameters
+ ----------
+ webhook_id : str
+ Unique identifier for a Webhook
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ import asyncio
+
+ from webflow import AsyncWebflow
client = AsyncWebflow(
access_token="YOUR_ACCESS_TOKEN",
)
- await client.webhooks.delete(
- webhook_id="webhook_id",
- )
+
+
+ async def main() -> None:
+ await client.webhooks.delete(
+ webhook_id="580e64008c9a982ac9b8b754",
+ )
+
+
+ asyncio.run(main())
"""
- _response = await self._client_wrapper.httpx_client.request(
- "DELETE",
- urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", f"webhooks/{jsonable_encoder(webhook_id)}"),
- params=jsonable_encoder(
- request_options.get("additional_query_parameters") if request_options is not None else None
- ),
- headers=jsonable_encoder(
- remove_none_from_dict(
- {
- **self._client_wrapper.get_headers(),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- timeout=request_options.get("timeout_in_seconds")
- if request_options is not None and request_options.get("timeout_in_seconds") is not None
- else 60,
- )
- if 200 <= _response.status_code < 300:
- return
- if _response.status_code == 400:
- raise BadRequestError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 401:
- raise UnauthorizedError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 404:
- raise NotFoundError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 429:
- raise TooManyRequestsError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- if _response.status_code == 500:
- raise InternalServerError(pydantic.parse_obj_as(typing.Any, _response.json())) # type: ignore
- try:
- _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)
+ _response = await self._raw_client.delete(webhook_id, request_options=request_options)
+ return _response.data
diff --git a/src/webflow/resources/webhooks/raw_client.py b/src/webflow/resources/webhooks/raw_client.py
new file mode 100644
index 0000000..ca4462d
--- /dev/null
+++ b/src/webflow/resources/webhooks/raw_client.py
@@ -0,0 +1,932 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+from json.decoder import JSONDecodeError
+
+from ...core.api_error import ApiError
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ...core.http_response import AsyncHttpResponse, HttpResponse
+from ...core.jsonable_encoder import jsonable_encoder
+from ...core.parse_error import ParsingError
+from ...core.pydantic_utilities import parse_obj_as
+from ...core.request_options import RequestOptions
+from ...core.serialization import convert_and_respect_annotation_metadata
+from ...errors.bad_request_error import BadRequestError
+from ...errors.internal_server_error import InternalServerError
+from ...errors.not_found_error import NotFoundError
+from ...errors.too_many_requests_error import TooManyRequestsError
+from ...errors.unauthorized_error import UnauthorizedError
+from ...types.error import Error
+from ...types.trigger_type import TriggerType
+from ...types.webhook import Webhook
+from ...types.webhook_filter import WebhookFilter
+from ...types.webhook_list import WebhookList
+from pydantic import ValidationError
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class RawWebhooksClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def list(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[WebhookList]:
+ """
+ List all App-created Webhooks registered for a given site
+
+ Required scope | `sites:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[WebhookList]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ WebhookList,
+ parse_obj_as(
+ type_=WebhookList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def create(
+ self,
+ site_id_: str,
+ *,
+ id: typing.Optional[str] = OMIT,
+ trigger_type: typing.Optional[TriggerType] = OMIT,
+ url: typing.Optional[str] = OMIT,
+ workspace_id: typing.Optional[str] = OMIT,
+ site_id: typing.Optional[str] = OMIT,
+ filter: typing.Optional[WebhookFilter] = OMIT,
+ last_triggered: typing.Optional[dt.datetime] = OMIT,
+ created_on: typing.Optional[dt.datetime] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[Webhook]:
+ """
+ Create a new Webhook.
+
+ Limit of 75 registrations per `triggerType`, per site.
+
+ Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients).
+ Required scope | `sites:write`
+
+ Parameters
+ ----------
+ site_id_ : str
+ Unique identifier for a Site
+
+ id : typing.Optional[str]
+ Unique identifier for the Webhook registration
+
+ trigger_type : typing.Optional[TriggerType]
+
+ url : typing.Optional[str]
+ URL to send the Webhook payload to
+
+ workspace_id : typing.Optional[str]
+ Unique identifier for the Workspace the Webhook is registered in
+
+ site_id : typing.Optional[str]
+ Unique identifier for the Site the Webhook is registered in
+
+ filter : typing.Optional[WebhookFilter]
+ Only supported for the `form_submission` trigger type. Filter for the form you want Webhooks to be sent for.
+
+ last_triggered : typing.Optional[dt.datetime]
+ Date the Webhook instance was last triggered
+
+ created_on : typing.Optional[dt.datetime]
+ Date the Webhook registration was created
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Webhook]
+ Request was successful
+ """
+ _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,
+ "triggerType": trigger_type,
+ "url": url,
+ "workspaceId": workspace_id,
+ "siteId": site_id,
+ "filter": convert_and_respect_annotation_metadata(
+ object_=filter, annotation=WebhookFilter, direction="write"
+ ),
+ "lastTriggered": last_triggered,
+ "createdOn": created_on,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Webhook,
+ parse_obj_as(
+ type_=Webhook, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def get(self, webhook_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[Webhook]:
+ """
+ Get a specific Webhook instance
+
+ Required scope: `sites:read`
+
+ Parameters
+ ----------
+ webhook_id : str
+ Unique identifier for a Webhook
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[Webhook]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Webhook,
+ parse_obj_as(
+ type_=Webhook, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def delete(self, webhook_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[None]:
+ """
+ Remove a Webhook
+
+ Required scope: `sites:read`
+
+ Parameters
+ ----------
+ webhook_id : str
+ Unique identifier for a Webhook
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[None]
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return HttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawWebhooksClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def list(
+ self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[WebhookList]:
+ """
+ List all App-created Webhooks registered for a given site
+
+ Required scope | `sites:read`
+
+ Parameters
+ ----------
+ site_id : str
+ Unique identifier for a Site
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[WebhookList]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ WebhookList,
+ parse_obj_as(
+ type_=WebhookList, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def create(
+ self,
+ site_id_: str,
+ *,
+ id: typing.Optional[str] = OMIT,
+ trigger_type: typing.Optional[TriggerType] = OMIT,
+ url: typing.Optional[str] = OMIT,
+ workspace_id: typing.Optional[str] = OMIT,
+ site_id: typing.Optional[str] = OMIT,
+ filter: typing.Optional[WebhookFilter] = OMIT,
+ last_triggered: typing.Optional[dt.datetime] = OMIT,
+ created_on: typing.Optional[dt.datetime] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[Webhook]:
+ """
+ Create a new Webhook.
+
+ Limit of 75 registrations per `triggerType`, per site.
+
+ Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients).
+ Required scope | `sites:write`
+
+ Parameters
+ ----------
+ site_id_ : str
+ Unique identifier for a Site
+
+ id : typing.Optional[str]
+ Unique identifier for the Webhook registration
+
+ trigger_type : typing.Optional[TriggerType]
+
+ url : typing.Optional[str]
+ URL to send the Webhook payload to
+
+ workspace_id : typing.Optional[str]
+ Unique identifier for the Workspace the Webhook is registered in
+
+ site_id : typing.Optional[str]
+ Unique identifier for the Site the Webhook is registered in
+
+ filter : typing.Optional[WebhookFilter]
+ Only supported for the `form_submission` trigger type. Filter for the form you want Webhooks to be sent for.
+
+ last_triggered : typing.Optional[dt.datetime]
+ Date the Webhook instance was last triggered
+
+ created_on : typing.Optional[dt.datetime]
+ Date the Webhook registration was created
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Webhook]
+ Request was successful
+ """
+ _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,
+ "triggerType": trigger_type,
+ "url": url,
+ "workspaceId": workspace_id,
+ "siteId": site_id,
+ "filter": convert_and_respect_annotation_metadata(
+ object_=filter, annotation=WebhookFilter, direction="write"
+ ),
+ "lastTriggered": last_triggered,
+ "createdOn": created_on,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Webhook,
+ parse_obj_as(
+ type_=Webhook, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def get(
+ self, webhook_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[Webhook]:
+ """
+ Get a specific Webhook instance
+
+ Required scope: `sites:read`
+
+ Parameters
+ ----------
+ webhook_id : str
+ Unique identifier for a Webhook
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[Webhook]
+ Request was successful
+ """
+ _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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ Webhook,
+ parse_obj_as(
+ type_=Webhook, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def delete(
+ self, webhook_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[None]:
+ """
+ Remove a Webhook
+
+ Required scope: `sites:read`
+
+ Parameters
+ ----------
+ webhook_id : str
+ Unique identifier for a Webhook
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[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,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return AsyncHttpResponse(response=_response, data=None)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/workspaces/__init__.py b/src/webflow/resources/workspaces/__init__.py
new file mode 100644
index 0000000..dd54dbd
--- /dev/null
+++ b/src/webflow/resources/workspaces/__init__.py
@@ -0,0 +1,46 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .resources import (
+ AuditLogsGetWorkspaceAuditLogsRequestEventType,
+ AuditLogsGetWorkspaceAuditLogsRequestSortOrder,
+ audit_logs,
+ )
+_dynamic_imports: typing.Dict[str, str] = {
+ "AuditLogsGetWorkspaceAuditLogsRequestEventType": ".resources",
+ "AuditLogsGetWorkspaceAuditLogsRequestSortOrder": ".resources",
+ "audit_logs": ".resources",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = [
+ "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..4b6aa91
--- /dev/null
+++ b/src/webflow/resources/workspaces/client.py
@@ -0,0 +1,63 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from __future__ import annotations
+
+import typing
+
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .raw_client import AsyncRawWorkspacesClient, RawWorkspacesClient
+
+if typing.TYPE_CHECKING:
+ from .resources.audit_logs.client import AsyncAuditLogsClient, AuditLogsClient
+
+
+class WorkspacesClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._raw_client = RawWorkspacesClient(client_wrapper=client_wrapper)
+ self._client_wrapper = client_wrapper
+ self._audit_logs: typing.Optional[AuditLogsClient] = None
+
+ @property
+ def with_raw_response(self) -> RawWorkspacesClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawWorkspacesClient
+ """
+ return self._raw_client
+
+ @property
+ def audit_logs(self):
+ if self._audit_logs is None:
+ from .resources.audit_logs.client import AuditLogsClient # noqa: E402
+
+ self._audit_logs = AuditLogsClient(client_wrapper=self._client_wrapper)
+ return self._audit_logs
+
+
+class AsyncWorkspacesClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._raw_client = AsyncRawWorkspacesClient(client_wrapper=client_wrapper)
+ self._client_wrapper = client_wrapper
+ self._audit_logs: typing.Optional[AsyncAuditLogsClient] = None
+
+ @property
+ def with_raw_response(self) -> AsyncRawWorkspacesClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawWorkspacesClient
+ """
+ return self._raw_client
+
+ @property
+ def audit_logs(self):
+ if self._audit_logs is None:
+ from .resources.audit_logs.client import AsyncAuditLogsClient # noqa: E402
+
+ self._audit_logs = AsyncAuditLogsClient(client_wrapper=self._client_wrapper)
+ return self._audit_logs
diff --git a/src/webflow/resources/workspaces/raw_client.py b/src/webflow/resources/workspaces/raw_client.py
new file mode 100644
index 0000000..8e98606
--- /dev/null
+++ b/src/webflow/resources/workspaces/raw_client.py
@@ -0,0 +1,13 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+
+
+class RawWorkspacesClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+
+class AsyncRawWorkspacesClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = 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..a7bfbd2
--- /dev/null
+++ b/src/webflow/resources/workspaces/resources/__init__.py
@@ -0,0 +1,46 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from . import audit_logs
+ from .audit_logs import (
+ AuditLogsGetWorkspaceAuditLogsRequestEventType,
+ AuditLogsGetWorkspaceAuditLogsRequestSortOrder,
+ )
+_dynamic_imports: typing.Dict[str, str] = {
+ "AuditLogsGetWorkspaceAuditLogsRequestEventType": ".audit_logs",
+ "AuditLogsGetWorkspaceAuditLogsRequestSortOrder": ".audit_logs",
+ "audit_logs": ".audit_logs",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = [
+ "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..2e698bb
--- /dev/null
+++ b/src/webflow/resources/workspaces/resources/audit_logs/__init__.py
@@ -0,0 +1,37 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .types import AuditLogsGetWorkspaceAuditLogsRequestEventType, AuditLogsGetWorkspaceAuditLogsRequestSortOrder
+_dynamic_imports: typing.Dict[str, str] = {
+ "AuditLogsGetWorkspaceAuditLogsRequestEventType": ".types",
+ "AuditLogsGetWorkspaceAuditLogsRequestSortOrder": ".types",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = ["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..2572f43
--- /dev/null
+++ b/src/webflow/resources/workspaces/resources/audit_logs/client.py
@@ -0,0 +1,220 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .....core.request_options import RequestOptions
+from .....types.workspace_audit_log_response import WorkspaceAuditLogResponse
+from .raw_client import AsyncRawAuditLogsClient, RawAuditLogsClient
+from .types.audit_logs_get_workspace_audit_logs_request_event_type import AuditLogsGetWorkspaceAuditLogsRequestEventType
+from .types.audit_logs_get_workspace_audit_logs_request_sort_order import AuditLogsGetWorkspaceAuditLogsRequestSortOrder
+
+
+class AuditLogsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._raw_client = RawAuditLogsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawAuditLogsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawAuditLogsClient
+ """
+ return self._raw_client
+
+ def get_workspace_audit_logs(
+ self,
+ workspace_id_or_slug: str,
+ *,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = 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[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ 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",
+ limit=1,
+ offset=1,
+ sort_order="asc",
+ event_type="user_access",
+ from_=datetime.datetime.fromisoformat(
+ "2025-06-22 16:00:31+00:00",
+ ),
+ to=datetime.datetime.fromisoformat(
+ "2025-07-22 16:00:31+00:00",
+ ),
+ )
+ """
+ _response = self._raw_client.get_workspace_audit_logs(
+ workspace_id_or_slug,
+ limit=limit,
+ offset=offset,
+ sort_order=sort_order,
+ event_type=event_type,
+ from_=from_,
+ to=to,
+ request_options=request_options,
+ )
+ return _response.data
+
+
+class AsyncAuditLogsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._raw_client = AsyncRawAuditLogsClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawAuditLogsClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawAuditLogsClient
+ """
+ return self._raw_client
+
+ async def get_workspace_audit_logs(
+ self,
+ workspace_id_or_slug: str,
+ *,
+ limit: typing.Optional[int] = None,
+ offset: typing.Optional[int] = 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[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ 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",
+ limit=1,
+ offset=1,
+ sort_order="asc",
+ event_type="user_access",
+ from_=datetime.datetime.fromisoformat(
+ "2025-06-22 16:00:31+00:00",
+ ),
+ to=datetime.datetime.fromisoformat(
+ "2025-07-22 16:00:31+00:00",
+ ),
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.get_workspace_audit_logs(
+ workspace_id_or_slug,
+ limit=limit,
+ offset=offset,
+ sort_order=sort_order,
+ event_type=event_type,
+ from_=from_,
+ to=to,
+ request_options=request_options,
+ )
+ return _response.data
diff --git a/src/webflow/resources/workspaces/resources/audit_logs/raw_client.py b/src/webflow/resources/workspaces/resources/audit_logs/raw_client.py
new file mode 100644
index 0000000..276afcc
--- /dev/null
+++ b/src/webflow/resources/workspaces/resources/audit_logs/raw_client.py
@@ -0,0 +1,310 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+from json.decoder import JSONDecodeError
+
+from .....core.api_error import ApiError
+from .....core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .....core.datetime_utils import serialize_datetime
+from .....core.http_response import AsyncHttpResponse, HttpResponse
+from .....core.jsonable_encoder import jsonable_encoder
+from .....core.parse_error import ParsingError
+from .....core.pydantic_utilities import parse_obj_as
+from .....core.request_options import RequestOptions
+from .....errors.forbidden_error import ForbiddenError
+from .....errors.internal_server_error import InternalServerError
+from .....errors.not_found_error import NotFoundError
+from .....errors.too_many_requests_error import TooManyRequestsError
+from .....errors.unauthorized_error import UnauthorizedError
+from .....types.error import Error
+from .....types.workspace_audit_log_response import WorkspaceAuditLogResponse
+from .types.audit_logs_get_workspace_audit_logs_request_event_type import AuditLogsGetWorkspaceAuditLogsRequestEventType
+from .types.audit_logs_get_workspace_audit_logs_request_sort_order import AuditLogsGetWorkspaceAuditLogsRequestSortOrder
+from pydantic import ValidationError
+
+
+class RawAuditLogsClient:
+ 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[int] = None,
+ offset: typing.Optional[int] = 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,
+ ) -> HttpResponse[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[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ 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
+ -------
+ HttpResponse[WorkspaceAuditLogResponse]
+ A list of workspace audit logs
+ """
+ _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:
+ _data = typing.cast(
+ WorkspaceAuditLogResponse,
+ parse_obj_as(
+ type_=WorkspaceAuditLogResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+
+class AsyncRawAuditLogsClient:
+ 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[int] = None,
+ offset: typing.Optional[int] = 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,
+ ) -> AsyncHttpResponse[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[int]
+ Maximum number of records to be returned (max limit: 100)
+
+ offset : typing.Optional[int]
+ Offset used for pagination if the results have more than limit records
+
+ 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
+ -------
+ AsyncHttpResponse[WorkspaceAuditLogResponse]
+ A list of workspace audit logs
+ """
+ _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:
+ _data = typing.cast(
+ WorkspaceAuditLogResponse,
+ parse_obj_as(
+ type_=WorkspaceAuditLogResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 429:
+ raise TooManyRequestsError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ Error,
+ parse_obj_as(
+ type_=Error, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/webflow/resources/workspaces/resources/audit_logs/types/__init__.py b/src/webflow/resources/workspaces/resources/audit_logs/types/__init__.py
new file mode 100644
index 0000000..c54f614
--- /dev/null
+++ b/src/webflow/resources/workspaces/resources/audit_logs/types/__init__.py
@@ -0,0 +1,38 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .audit_logs_get_workspace_audit_logs_request_event_type import AuditLogsGetWorkspaceAuditLogsRequestEventType
+ from .audit_logs_get_workspace_audit_logs_request_sort_order import AuditLogsGetWorkspaceAuditLogsRequestSortOrder
+_dynamic_imports: typing.Dict[str, str] = {
+ "AuditLogsGetWorkspaceAuditLogsRequestEventType": ".audit_logs_get_workspace_audit_logs_request_event_type",
+ "AuditLogsGetWorkspaceAuditLogsRequestSortOrder": ".audit_logs_get_workspace_audit_logs_request_sort_order",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = ["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..08c3185
--- /dev/null
+++ b/src/webflow/resources/workspaces/resources/audit_logs/types/audit_logs_get_workspace_audit_logs_request_event_type.py
@@ -0,0 +1,15 @@
+# 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",
+ "workspace_setting",
+ ],
+ 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 dc0bb64..88c0cbd 100644
--- a/src/webflow/types/__init__.py
+++ b/src/webflow/types/__init__.py
@@ -1,129 +1,603 @@
# This file was auto-generated by Fern from our API Definition.
-from .access_group import AccessGroup
-from .access_group_list import AccessGroupList
-from .application import Application
-from .asset import Asset
-from .asset_folder import AssetFolder
-from .asset_folder_list import AssetFolderList
-from .asset_upload import AssetUpload
-from .asset_upload_upload_details import AssetUploadUploadDetails
-from .asset_variant import AssetVariant
-from .assets import Assets
-from .authorization import Authorization
-from .authorization_authorization import AuthorizationAuthorization
-from .authorization_authorization_authorized_to import AuthorizationAuthorizationAuthorizedTo
-from .authorized_user import AuthorizedUser
-from .collection import Collection
-from .collection_item import CollectionItem
-from .collection_item_field_data import CollectionItemFieldData
-from .collection_item_list import CollectionItemList
-from .collection_item_list_pagination import CollectionItemListPagination
-from .collection_list import CollectionList
-from .collection_list_array_item import CollectionListArrayItem
-from .custom_code_block import CustomCodeBlock
-from .custom_code_block_type import CustomCodeBlockType
-from .custom_code_response import CustomCodeResponse
-from .dom import Dom
-from .domain import Domain
-from .domains import Domains
-from .duplicate_user_email import DuplicateUserEmail
-from .ecommerce_settings import EcommerceSettings
-from .error import Error
-from .error_details_item import ErrorDetailsItem
-from .field import Field
-from .field_type import FieldType
-from .form import Form
-from .form_field import FormField
-from .form_field_value import FormFieldValue
-from .form_field_value_type import FormFieldValueType
-from .form_list import FormList
-from .form_response_settings import FormResponseSettings
-from .form_submission import FormSubmission
-from .form_submission_list import FormSubmissionList
-from .image_node import ImageNode
-from .invalid_domain import InvalidDomain
-from .inventory_item import InventoryItem
-from .inventory_item_inventory_type import InventoryItemInventoryType
-from .list_custom_code_blocks import ListCustomCodeBlocks
-from .missing_scopes import MissingScopes
-from .no_domains import NoDomains
-from .node import Node
-from .node_type import NodeType
-from .not_enterprise_plan_site import NotEnterprisePlanSite
-from .oauth_scope import OauthScope
-from .order import Order
-from .order_address import OrderAddress
-from .order_address_japan_type import OrderAddressJapanType
-from .order_address_type import OrderAddressType
-from .order_customer_info import OrderCustomerInfo
-from .order_dispute_last_status import OrderDisputeLastStatus
-from .order_download_files_item import OrderDownloadFilesItem
-from .order_list import OrderList
-from .order_metadata import OrderMetadata
-from .order_price import OrderPrice
-from .order_purchased_item import OrderPurchasedItem
-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_status import OrderStatus
-from .order_totals import OrderTotals
-from .order_totals_extras_item import OrderTotalsExtrasItem
-from .order_totals_extras_item_type import OrderTotalsExtrasItemType
-from .page import Page
-from .page_list import PageList
-from .page_open_graph import PageOpenGraph
-from .page_seo import PageSeo
-from .pagination import Pagination
-from .paypal_details import PaypalDetails
-from .product import Product
-from .product_and_sk_us import ProductAndSkUs
-from .product_and_sk_us_list import ProductAndSkUsList
-from .product_field_data import ProductFieldData
-from .product_field_data_ec_product_type import ProductFieldDataEcProductType
-from .product_field_data_tax_category import ProductFieldDataTaxCategory
-from .publish_status import PublishStatus
-from .registered_script_list import RegisteredScriptList
-from .script_apply import ScriptApply
-from .script_apply_list import ScriptApplyList
-from .script_apply_location import ScriptApplyLocation
-from .scripts import Scripts
-from .site import Site
-from .site_activity_log_item import SiteActivityLogItem
-from .site_activity_log_item_resource_operation import SiteActivityLogItemResourceOperation
-from .site_activity_log_item_user import SiteActivityLogItemUser
-from .site_activity_log_response import SiteActivityLogResponse
-from .sku import Sku
-from .sku_field_data import SkuFieldData
-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_field_data_ec_sku_subscription_plan_interval import SkuFieldDataEcSkuSubscriptionPlanInterval
-from .sku_field_data_price import SkuFieldDataPrice
-from .sku_property_list import SkuPropertyList
-from .sku_property_list_enum_item import SkuPropertyListEnumItem
-from .sku_value_list import SkuValueList
-from .stripe_card import StripeCard
-from .stripe_card_brand import StripeCardBrand
-from .stripe_card_expires import StripeCardExpires
-from .stripe_details import StripeDetails
-from .text_node import TextNode
-from .trigger_type import TriggerType
-from .user import User
-from .user_access_groups_item import UserAccessGroupsItem
-from .user_access_groups_item_type import UserAccessGroupsItemType
-from .user_data import UserData
-from .user_data_data import UserDataData
-from .user_limit_reached import UserLimitReached
-from .user_list import UserList
-from .user_status import UserStatus
-from .users_not_enabled import UsersNotEnabled
-from .webhook import Webhook
-from .webhook_list import WebhookList
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .application import Application
+ from .asset import Asset
+ from .asset_folder import AssetFolder
+ from .asset_folder_list import AssetFolderList
+ from .asset_upload import AssetUpload
+ from .asset_upload_upload_details import AssetUploadUploadDetails
+ from .asset_variant import AssetVariant
+ from .assets import Assets
+ from .authorization import Authorization
+ from .authorization_authorization import AuthorizationAuthorization
+ from .authorization_authorization_authorized_to import AuthorizationAuthorizationAuthorizedTo
+ from .authorized_user import AuthorizedUser
+ from .bad_request_error_body import BadRequestErrorBody
+ from .bulk_collection_item import BulkCollectionItem
+ from .bulk_collection_item_field_data import BulkCollectionItemFieldData
+ from .collection import Collection
+ from .collection_item import CollectionItem
+ from .collection_item_changed import CollectionItemChanged
+ from .collection_item_created import CollectionItemCreated
+ from .collection_item_field_data import CollectionItemFieldData
+ from .collection_item_list import CollectionItemList
+ from .collection_item_list_no_pagination import CollectionItemListNoPagination
+ from .collection_item_list_pagination import CollectionItemListPagination
+ from .collection_item_patch_single import CollectionItemPatchSingle
+ from .collection_item_patch_single_field_data import CollectionItemPatchSingleFieldData
+ from .collection_item_post_single import CollectionItemPostSingle
+ from .collection_item_post_single_field_data import CollectionItemPostSingleFieldData
+ from .collection_item_published import CollectionItemPublished
+ from .collection_item_removed import CollectionItemRemoved
+ from .collection_item_removed_payload import CollectionItemRemovedPayload
+ from .collection_item_removed_payload_field_data import CollectionItemRemovedPayloadFieldData
+ from .collection_item_unpublished import CollectionItemUnpublished
+ from .collection_item_unpublished_payload import CollectionItemUnpublishedPayload
+ from .collection_item_unpublished_payload_field_data import CollectionItemUnpublishedPayloadFieldData
+ from .collection_item_with_id_input import CollectionItemWithIdInput
+ from .collection_item_with_id_input_field_data import CollectionItemWithIdInputFieldData
+ from .collection_list import CollectionList
+ from .collection_list_array_item import CollectionListArrayItem
+ from .comment import Comment
+ from .comment_payload import CommentPayload
+ from .comment_payload_author import CommentPayloadAuthor
+ from .comment_payload_mentioned_users_item import CommentPayloadMentionedUsersItem
+ 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_node_property_overrides_write_property_overrides_item import (
+ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem,
+ )
+ from .component_list import ComponentList
+ from .component_node import ComponentNode
+ from .component_properties import ComponentProperties
+ from .component_property import ComponentProperty
+ from .component_property_type import ComponentPropertyType
+ from .conflict import Conflict
+ from .custom_code_block import CustomCodeBlock
+ from .custom_code_block_type import CustomCodeBlockType
+ from .custom_code_hosted_response import CustomCodeHostedResponse
+ from .custom_code_inline_response import CustomCodeInlineResponse
+ from .custom_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
+ from .ecommerce_settings import EcommerceSettings
+ 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
+ from .form_field_value import FormFieldValue
+ from .form_field_value_type import FormFieldValueType
+ from .form_list import FormList
+ from .form_response_settings import FormResponseSettings
+ from .form_submission import FormSubmission
+ from .form_submission_list import FormSubmissionList
+ from .form_submission_trigger import FormSubmissionTrigger
+ from .form_submission_trigger_payload import FormSubmissionTriggerPayload
+ from .form_submission_trigger_payload_schema_item import FormSubmissionTriggerPayloadSchemaItem
+ from .form_submission_trigger_payload_schema_item_field_type import FormSubmissionTriggerPayloadSchemaItemFieldType
+ from .image_node import ImageNode
+ from .image_node_image import ImageNodeImage
+ from .invalid_domain import InvalidDomain
+ from .invalid_scopes import InvalidScopes
+ from .inventory_item import InventoryItem
+ from .inventory_item_inventory_type import InventoryItemInventoryType
+ from .items_list_items_live_request_last_published import ItemsListItemsLiveRequestLastPublished
+ from .items_list_items_request_last_published import ItemsListItemsRequestLastPublished
+ 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 .new_order import NewOrder
+ from .no_domains import NoDomains
+ 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
+ from .order_list import OrderList
+ from .order_metadata import OrderMetadata
+ from .order_price import OrderPrice
+ from .order_purchased_item import OrderPurchasedItem
+ 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
+ from .order_totals_extras_item_type import OrderTotalsExtrasItemType
+ from .page import Page
+ from .page_created_webhook import PageCreatedWebhook
+ from .page_created_webhook_payload import PageCreatedWebhookPayload
+ from .page_deleted_webhook import PageDeletedWebhook
+ from .page_deleted_webhook_payload import PageDeletedWebhookPayload
+ from .page_list import PageList
+ from .page_metadata_updated_webhook import PageMetadataUpdatedWebhook
+ from .page_metadata_updated_webhook_payload import PageMetadataUpdatedWebhookPayload
+ from .page_open_graph import PageOpenGraph
+ from .page_seo import PageSeo
+ from .pagination import Pagination
+ from .payload import Payload
+ from .payload_field_data import PayloadFieldData
+ from .paypal_details import PaypalDetails
+ from .product import Product
+ from .product_and_sk_us import ProductAndSkUs
+ from .product_and_sk_us_list import ProductAndSkUsList
+ from .product_field_data import ProductFieldData
+ from .product_field_data_ec_product_type import ProductFieldDataEcProductType
+ from .product_field_data_tax_category import ProductFieldDataTaxCategory
+ 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_node import SearchButtonNode
+ from .search_button_node_write import SearchButtonNodeWrite
+ 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 .setting_change import SettingChange
+ from .setting_change_audit_log_item import SettingChangeAuditLogItem
+ from .single_locale_created_payload import SingleLocaleCreatedPayload
+ from .single_locale_created_payload_field_data import SingleLocaleCreatedPayloadFieldData
+ from .site import Site
+ from .site_activity_log_item import SiteActivityLogItem
+ from .site_activity_log_item_event import SiteActivityLogItemEvent
+ from .site_activity_log_item_resource_operation import SiteActivityLogItemResourceOperation
+ 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
+ from .site_publish import SitePublish
+ from .site_publish_payload import SitePublishPayload
+ from .sites import Sites
+ from .sku import Sku
+ from .sku_field_data import SkuFieldData
+ 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_field_data_ec_sku_subscription_plan_interval import SkuFieldDataEcSkuSubscriptionPlanInterval
+ from .sku_field_data_ec_sku_subscription_plan_plans_item import SkuFieldDataEcSkuSubscriptionPlanPlansItem
+ from .sku_field_data_ec_sku_subscription_plan_plans_item_status import (
+ SkuFieldDataEcSkuSubscriptionPlanPlansItemStatus,
+ )
+ from .sku_field_data_price import SkuFieldDataPrice
+ 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_node import SubmitButtonNode
+ from .submit_button_node_write import SubmitButtonNodeWrite
+ from .text import Text
+ from .text_input_node import TextInputNode
+ from .text_input_node_write import TextInputNodeWrite
+ from .text_node import TextNode
+ from .text_node_text import TextNodeText
+ from .text_node_write import TextNodeWrite
+ from .trigger_type import TriggerType
+ from .updated_order import UpdatedOrder
+ 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 .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,
+ WorkspaceAuditLogItem_WorkspaceSetting,
+ )
+ from .workspace_audit_log_item_actor import WorkspaceAuditLogItemActor
+ from .workspace_audit_log_item_payload_setting_change_method import WorkspaceAuditLogItemPayloadSettingChangeMethod
+ from .workspace_audit_log_item_payload_site_membership_granular_access import (
+ WorkspaceAuditLogItemPayloadSiteMembershipGranularAccess,
+ )
+ 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_target_users_item import (
+ WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUsersItem,
+ )
+ 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
+_dynamic_imports: typing.Dict[str, str] = {
+ "Application": ".application",
+ "Asset": ".asset",
+ "AssetFolder": ".asset_folder",
+ "AssetFolderList": ".asset_folder_list",
+ "AssetUpload": ".asset_upload",
+ "AssetUploadUploadDetails": ".asset_upload_upload_details",
+ "AssetVariant": ".asset_variant",
+ "Assets": ".assets",
+ "Authorization": ".authorization",
+ "AuthorizationAuthorization": ".authorization_authorization",
+ "AuthorizationAuthorizationAuthorizedTo": ".authorization_authorization_authorized_to",
+ "AuthorizedUser": ".authorized_user",
+ "BadRequestErrorBody": ".bad_request_error_body",
+ "BulkCollectionItem": ".bulk_collection_item",
+ "BulkCollectionItemFieldData": ".bulk_collection_item_field_data",
+ "Collection": ".collection",
+ "CollectionItem": ".collection_item",
+ "CollectionItemChanged": ".collection_item_changed",
+ "CollectionItemCreated": ".collection_item_created",
+ "CollectionItemFieldData": ".collection_item_field_data",
+ "CollectionItemList": ".collection_item_list",
+ "CollectionItemListNoPagination": ".collection_item_list_no_pagination",
+ "CollectionItemListPagination": ".collection_item_list_pagination",
+ "CollectionItemPatchSingle": ".collection_item_patch_single",
+ "CollectionItemPatchSingleFieldData": ".collection_item_patch_single_field_data",
+ "CollectionItemPostSingle": ".collection_item_post_single",
+ "CollectionItemPostSingleFieldData": ".collection_item_post_single_field_data",
+ "CollectionItemPublished": ".collection_item_published",
+ "CollectionItemRemoved": ".collection_item_removed",
+ "CollectionItemRemovedPayload": ".collection_item_removed_payload",
+ "CollectionItemRemovedPayloadFieldData": ".collection_item_removed_payload_field_data",
+ "CollectionItemUnpublished": ".collection_item_unpublished",
+ "CollectionItemUnpublishedPayload": ".collection_item_unpublished_payload",
+ "CollectionItemUnpublishedPayloadFieldData": ".collection_item_unpublished_payload_field_data",
+ "CollectionItemWithIdInput": ".collection_item_with_id_input",
+ "CollectionItemWithIdInputFieldData": ".collection_item_with_id_input_field_data",
+ "CollectionList": ".collection_list",
+ "CollectionListArrayItem": ".collection_list_array_item",
+ "Comment": ".comment",
+ "CommentPayload": ".comment_payload",
+ "CommentPayloadAuthor": ".comment_payload_author",
+ "CommentPayloadMentionedUsersItem": ".comment_payload_mentioned_users_item",
+ "CommentReply": ".comment_reply",
+ "CommentReplyAuthor": ".comment_reply_author",
+ "CommentReplyList": ".comment_reply_list",
+ "CommentReplyListPagination": ".comment_reply_list_pagination",
+ "CommentReplyMentionedUsersItem": ".comment_reply_mentioned_users_item",
+ "CommentThread": ".comment_thread",
+ "CommentThreadAuthor": ".comment_thread_author",
+ "CommentThreadList": ".comment_thread_list",
+ "CommentThreadListPagination": ".comment_thread_list_pagination",
+ "CommentThreadMentionedUsersItem": ".comment_thread_mentioned_users_item",
+ "Component": ".component",
+ "ComponentDom": ".component_dom",
+ "ComponentInstanceNodePropertyOverridesWrite": ".component_instance_node_property_overrides_write",
+ "ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem": ".component_instance_node_property_overrides_write_property_overrides_item",
+ "ComponentList": ".component_list",
+ "ComponentNode": ".component_node",
+ "ComponentProperties": ".component_properties",
+ "ComponentProperty": ".component_property",
+ "ComponentPropertyType": ".component_property_type",
+ "Conflict": ".conflict",
+ "CustomCodeBlock": ".custom_code_block",
+ "CustomCodeBlockType": ".custom_code_block_type",
+ "CustomCodeHostedResponse": ".custom_code_hosted_response",
+ "CustomCodeInlineResponse": ".custom_code_inline_response",
+ "CustomRole": ".custom_role",
+ "CustomRoleAuditLogItem": ".custom_role_audit_log_item",
+ "CustomRoleAuditLogItemEventSubType": ".custom_role_audit_log_item_event_sub_type",
+ "Dom": ".dom",
+ "Domain": ".domain",
+ "Domains": ".domains",
+ "EcommerceSettings": ".ecommerce_settings",
+ "Error": ".error",
+ "ErrorCode": ".error_code",
+ "Field": ".field",
+ "FieldCreate": ".field_create",
+ "FieldType": ".field_type",
+ "FieldValidations": ".field_validations",
+ "FieldValidationsAdditionalProperties": ".field_validations_additional_properties",
+ "FieldValidationsAdditionalPropertiesAdditionalProperties": ".field_validations_additional_properties_additional_properties",
+ "ForbiddenErrorBody": ".forbidden_error_body",
+ "Form": ".form",
+ "FormField": ".form_field",
+ "FormFieldValue": ".form_field_value",
+ "FormFieldValueType": ".form_field_value_type",
+ "FormList": ".form_list",
+ "FormResponseSettings": ".form_response_settings",
+ "FormSubmission": ".form_submission",
+ "FormSubmissionList": ".form_submission_list",
+ "FormSubmissionTrigger": ".form_submission_trigger",
+ "FormSubmissionTriggerPayload": ".form_submission_trigger_payload",
+ "FormSubmissionTriggerPayloadSchemaItem": ".form_submission_trigger_payload_schema_item",
+ "FormSubmissionTriggerPayloadSchemaItemFieldType": ".form_submission_trigger_payload_schema_item_field_type",
+ "ImageNode": ".image_node",
+ "ImageNodeImage": ".image_node_image",
+ "InvalidDomain": ".invalid_domain",
+ "InvalidScopes": ".invalid_scopes",
+ "InventoryItem": ".inventory_item",
+ "InventoryItemInventoryType": ".inventory_item_inventory_type",
+ "ItemsListItemsLiveRequestLastPublished": ".items_list_items_live_request_last_published",
+ "ItemsListItemsRequestLastPublished": ".items_list_items_request_last_published",
+ "ListCustomCodeBlocks": ".list_custom_code_blocks",
+ "Locale": ".locale",
+ "Locales": ".locales",
+ "Metadata": ".metadata",
+ "MetadataOptionsItem": ".metadata_options_item",
+ "NewOrder": ".new_order",
+ "NoDomains": ".no_domains",
+ "Node": ".node",
+ "Node_ComponentInstance": ".node",
+ "Node_Image": ".node",
+ "Node_SearchButton": ".node",
+ "Node_Select": ".node",
+ "Node_SubmitButton": ".node",
+ "Node_Text": ".node",
+ "Node_TextInput": ".node",
+ "NotEnterprisePlanSite": ".not_enterprise_plan_site",
+ "NotEnterprisePlanWorkspace": ".not_enterprise_plan_workspace",
+ "OptionField": ".option_field",
+ "Order": ".order",
+ "OrderAddress": ".order_address",
+ "OrderAddressJapanType": ".order_address_japan_type",
+ "OrderAddressType": ".order_address_type",
+ "OrderBillingAddress": ".order_billing_address",
+ "OrderBillingAddressJapanType": ".order_billing_address_japan_type",
+ "OrderBillingAddressType": ".order_billing_address_type",
+ "OrderCustomerInfo": ".order_customer_info",
+ "OrderDisputeLastStatus": ".order_dispute_last_status",
+ "OrderDownloadFilesItem": ".order_download_files_item",
+ "OrderList": ".order_list",
+ "OrderMetadata": ".order_metadata",
+ "OrderPrice": ".order_price",
+ "OrderPurchasedItem": ".order_purchased_item",
+ "OrderPurchasedItemVariantImage": ".order_purchased_item_variant_image",
+ "OrderPurchasedItemVariantImageFile": ".order_purchased_item_variant_image_file",
+ "OrderPurchasedItemVariantImageFileVariantsItem": ".order_purchased_item_variant_image_file_variants_item",
+ "OrderShippingAddress": ".order_shipping_address",
+ "OrderShippingAddressJapanType": ".order_shipping_address_japan_type",
+ "OrderShippingAddressType": ".order_shipping_address_type",
+ "OrderStatus": ".order_status",
+ "OrderTotals": ".order_totals",
+ "OrderTotalsExtrasItem": ".order_totals_extras_item",
+ "OrderTotalsExtrasItemType": ".order_totals_extras_item_type",
+ "Page": ".page",
+ "PageCreatedWebhook": ".page_created_webhook",
+ "PageCreatedWebhookPayload": ".page_created_webhook_payload",
+ "PageDeletedWebhook": ".page_deleted_webhook",
+ "PageDeletedWebhookPayload": ".page_deleted_webhook_payload",
+ "PageList": ".page_list",
+ "PageMetadataUpdatedWebhook": ".page_metadata_updated_webhook",
+ "PageMetadataUpdatedWebhookPayload": ".page_metadata_updated_webhook_payload",
+ "PageOpenGraph": ".page_open_graph",
+ "PageSeo": ".page_seo",
+ "Pagination": ".pagination",
+ "Payload": ".payload",
+ "PayloadFieldData": ".payload_field_data",
+ "PaypalDetails": ".paypal_details",
+ "Product": ".product",
+ "ProductAndSkUs": ".product_and_sk_us",
+ "ProductAndSkUsList": ".product_and_sk_us_list",
+ "ProductFieldData": ".product_field_data",
+ "ProductFieldDataEcProductType": ".product_field_data_ec_product_type",
+ "ProductFieldDataTaxCategory": ".product_field_data_tax_category",
+ "PublishStatus": ".publish_status",
+ "Redirect": ".redirect",
+ "Redirects": ".redirects",
+ "ReferenceField": ".reference_field",
+ "ReferenceFieldMetadata": ".reference_field_metadata",
+ "ReferenceFieldType": ".reference_field_type",
+ "RegisteredScriptList": ".registered_script_list",
+ "Robots": ".robots",
+ "RobotsRulesItem": ".robots_rules_item",
+ "ScriptApply": ".script_apply",
+ "ScriptApplyList": ".script_apply_list",
+ "ScriptApplyLocation": ".script_apply_location",
+ "Scripts": ".scripts",
+ "SearchButtonNode": ".search_button_node",
+ "SearchButtonNodeWrite": ".search_button_node_write",
+ "Select": ".select",
+ "SelectNode": ".select_node",
+ "SelectNodeChoicesItem": ".select_node_choices_item",
+ "SelectNodeWriteChoicesItem": ".select_node_write_choices_item",
+ "SettingChange": ".setting_change",
+ "SettingChangeAuditLogItem": ".setting_change_audit_log_item",
+ "SingleLocaleCreatedPayload": ".single_locale_created_payload",
+ "SingleLocaleCreatedPayloadFieldData": ".single_locale_created_payload_field_data",
+ "Site": ".site",
+ "SiteActivityLogItem": ".site_activity_log_item",
+ "SiteActivityLogItemEvent": ".site_activity_log_item_event",
+ "SiteActivityLogItemResourceOperation": ".site_activity_log_item_resource_operation",
+ "SiteActivityLogItemUser": ".site_activity_log_item_user",
+ "SiteActivityLogResponse": ".site_activity_log_response",
+ "SiteDataCollectionType": ".site_data_collection_type",
+ "SiteMembership": ".site_membership",
+ "SiteMembershipAuditLogItem": ".site_membership_audit_log_item",
+ "SiteMembershipAuditLogItemEventSubType": ".site_membership_audit_log_item_event_sub_type",
+ "SitePlan": ".site_plan",
+ "SitePlanId": ".site_plan_id",
+ "SitePlanName": ".site_plan_name",
+ "SitePublish": ".site_publish",
+ "SitePublishPayload": ".site_publish_payload",
+ "Sites": ".sites",
+ "Sku": ".sku",
+ "SkuFieldData": ".sku_field_data",
+ "SkuFieldDataCompareAtPrice": ".sku_field_data_compare_at_price",
+ "SkuFieldDataEcSkuBillingMethod": ".sku_field_data_ec_sku_billing_method",
+ "SkuFieldDataEcSkuSubscriptionPlan": ".sku_field_data_ec_sku_subscription_plan",
+ "SkuFieldDataEcSkuSubscriptionPlanInterval": ".sku_field_data_ec_sku_subscription_plan_interval",
+ "SkuFieldDataEcSkuSubscriptionPlanPlansItem": ".sku_field_data_ec_sku_subscription_plan_plans_item",
+ "SkuFieldDataEcSkuSubscriptionPlanPlansItemStatus": ".sku_field_data_ec_sku_subscription_plan_plans_item_status",
+ "SkuFieldDataPrice": ".sku_field_data_price",
+ "SkuPropertyList": ".sku_property_list",
+ "SkuPropertyListEnumItem": ".sku_property_list_enum_item",
+ "SkuValueList": ".sku_value_list",
+ "StaticField": ".static_field",
+ "StaticFieldType": ".static_field_type",
+ "StripeCard": ".stripe_card",
+ "StripeCardBrand": ".stripe_card_brand",
+ "StripeCardExpires": ".stripe_card_expires",
+ "StripeDetails": ".stripe_details",
+ "SubmitButtonNode": ".submit_button_node",
+ "SubmitButtonNodeWrite": ".submit_button_node_write",
+ "Text": ".text",
+ "TextInputNode": ".text_input_node",
+ "TextInputNodeWrite": ".text_input_node_write",
+ "TextNode": ".text_node",
+ "TextNodeText": ".text_node_text",
+ "TextNodeWrite": ".text_node_write",
+ "TriggerType": ".trigger_type",
+ "UpdatedOrder": ".updated_order",
+ "UserAccess": ".user_access",
+ "UserAccessAuditLogItem": ".user_access_audit_log_item",
+ "UserAccessAuditLogItemEventSubType": ".user_access_audit_log_item_event_sub_type",
+ "Webhook": ".webhook",
+ "WebhookFilter": ".webhook_filter",
+ "WebhookList": ".webhook_list",
+ "WorkspaceAuditLogItem": ".workspace_audit_log_item",
+ "WorkspaceAuditLogItemActor": ".workspace_audit_log_item_actor",
+ "WorkspaceAuditLogItemPayloadSettingChangeMethod": ".workspace_audit_log_item_payload_setting_change_method",
+ "WorkspaceAuditLogItemPayloadSiteMembershipGranularAccess": ".workspace_audit_log_item_payload_site_membership_granular_access",
+ "WorkspaceAuditLogItemPayloadSiteMembershipMethod": ".workspace_audit_log_item_payload_site_membership_method",
+ "WorkspaceAuditLogItemPayloadSiteMembershipSite": ".workspace_audit_log_item_payload_site_membership_site",
+ "WorkspaceAuditLogItemPayloadSiteMembershipTargetUser": ".workspace_audit_log_item_payload_site_membership_target_user",
+ "WorkspaceAuditLogItemPayloadSiteMembershipUserType": ".workspace_audit_log_item_payload_site_membership_user_type",
+ "WorkspaceAuditLogItemPayloadUserAccessMethod": ".workspace_audit_log_item_payload_user_access_method",
+ "WorkspaceAuditLogItemPayloadWorkspaceInvitationMethod": ".workspace_audit_log_item_payload_workspace_invitation_method",
+ "WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUser": ".workspace_audit_log_item_payload_workspace_invitation_target_user",
+ "WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUsersItem": ".workspace_audit_log_item_payload_workspace_invitation_target_users_item",
+ "WorkspaceAuditLogItemPayloadWorkspaceInvitationUserType": ".workspace_audit_log_item_payload_workspace_invitation_user_type",
+ "WorkspaceAuditLogItemPayloadWorkspaceMembershipMethod": ".workspace_audit_log_item_payload_workspace_membership_method",
+ "WorkspaceAuditLogItemPayloadWorkspaceMembershipTargetUser": ".workspace_audit_log_item_payload_workspace_membership_target_user",
+ "WorkspaceAuditLogItemPayloadWorkspaceMembershipUserType": ".workspace_audit_log_item_payload_workspace_membership_user_type",
+ "WorkspaceAuditLogItemWorkspace": ".workspace_audit_log_item_workspace",
+ "WorkspaceAuditLogItem_CustomRole": ".workspace_audit_log_item",
+ "WorkspaceAuditLogItem_SiteMembership": ".workspace_audit_log_item",
+ "WorkspaceAuditLogItem_UserAccess": ".workspace_audit_log_item",
+ "WorkspaceAuditLogItem_WorkspaceInvitation": ".workspace_audit_log_item",
+ "WorkspaceAuditLogItem_WorkspaceMembership": ".workspace_audit_log_item",
+ "WorkspaceAuditLogItem_WorkspaceSetting": ".workspace_audit_log_item",
+ "WorkspaceAuditLogResponse": ".workspace_audit_log_response",
+ "WorkspaceInvitation": ".workspace_invitation",
+ "WorkspaceInvitationAuditLogItem": ".workspace_invitation_audit_log_item",
+ "WorkspaceInvitationAuditLogItemEventSubType": ".workspace_invitation_audit_log_item_event_sub_type",
+ "WorkspaceMembership": ".workspace_membership",
+ "WorkspaceMembershipAuditLogItem": ".workspace_membership_audit_log_item",
+ "WorkspaceMembershipAuditLogItemEventSubType": ".workspace_membership_audit_log_item_event_sub_type",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
__all__ = [
- "AccessGroup",
- "AccessGroupList",
"Application",
"Asset",
"AssetFolder",
@@ -136,25 +610,76 @@
"AuthorizationAuthorization",
"AuthorizationAuthorizationAuthorizedTo",
"AuthorizedUser",
+ "BadRequestErrorBody",
+ "BulkCollectionItem",
+ "BulkCollectionItemFieldData",
"Collection",
"CollectionItem",
+ "CollectionItemChanged",
+ "CollectionItemCreated",
"CollectionItemFieldData",
"CollectionItemList",
+ "CollectionItemListNoPagination",
"CollectionItemListPagination",
+ "CollectionItemPatchSingle",
+ "CollectionItemPatchSingleFieldData",
+ "CollectionItemPostSingle",
+ "CollectionItemPostSingleFieldData",
+ "CollectionItemPublished",
+ "CollectionItemRemoved",
+ "CollectionItemRemovedPayload",
+ "CollectionItemRemovedPayloadFieldData",
+ "CollectionItemUnpublished",
+ "CollectionItemUnpublishedPayload",
+ "CollectionItemUnpublishedPayloadFieldData",
+ "CollectionItemWithIdInput",
+ "CollectionItemWithIdInputFieldData",
"CollectionList",
"CollectionListArrayItem",
+ "Comment",
+ "CommentPayload",
+ "CommentPayloadAuthor",
+ "CommentPayloadMentionedUsersItem",
+ "CommentReply",
+ "CommentReplyAuthor",
+ "CommentReplyList",
+ "CommentReplyListPagination",
+ "CommentReplyMentionedUsersItem",
+ "CommentThread",
+ "CommentThreadAuthor",
+ "CommentThreadList",
+ "CommentThreadListPagination",
+ "CommentThreadMentionedUsersItem",
+ "Component",
+ "ComponentDom",
+ "ComponentInstanceNodePropertyOverridesWrite",
+ "ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem",
+ "ComponentList",
+ "ComponentNode",
+ "ComponentProperties",
+ "ComponentProperty",
+ "ComponentPropertyType",
+ "Conflict",
"CustomCodeBlock",
"CustomCodeBlockType",
- "CustomCodeResponse",
+ "CustomCodeHostedResponse",
+ "CustomCodeInlineResponse",
+ "CustomRole",
+ "CustomRoleAuditLogItem",
+ "CustomRoleAuditLogItemEventSubType",
"Dom",
"Domain",
"Domains",
- "DuplicateUserEmail",
"EcommerceSettings",
"Error",
- "ErrorDetailsItem",
+ "ErrorCode",
"Field",
+ "FieldCreate",
"FieldType",
+ "FieldValidations",
+ "FieldValidationsAdditionalProperties",
+ "FieldValidationsAdditionalPropertiesAdditionalProperties",
+ "ForbiddenErrorBody",
"Form",
"FormField",
"FormFieldValue",
@@ -163,21 +688,43 @@
"FormResponseSettings",
"FormSubmission",
"FormSubmissionList",
+ "FormSubmissionTrigger",
+ "FormSubmissionTriggerPayload",
+ "FormSubmissionTriggerPayloadSchemaItem",
+ "FormSubmissionTriggerPayloadSchemaItemFieldType",
"ImageNode",
+ "ImageNodeImage",
"InvalidDomain",
+ "InvalidScopes",
"InventoryItem",
"InventoryItemInventoryType",
+ "ItemsListItemsLiveRequestLastPublished",
+ "ItemsListItemsRequestLastPublished",
"ListCustomCodeBlocks",
- "MissingScopes",
+ "Locale",
+ "Locales",
+ "Metadata",
+ "MetadataOptionsItem",
+ "NewOrder",
"NoDomains",
"Node",
- "NodeType",
+ "Node_ComponentInstance",
+ "Node_Image",
+ "Node_SearchButton",
+ "Node_Select",
+ "Node_SubmitButton",
+ "Node_Text",
+ "Node_TextInput",
"NotEnterprisePlanSite",
- "OauthScope",
+ "NotEnterprisePlanWorkspace",
+ "OptionField",
"Order",
"OrderAddress",
"OrderAddressJapanType",
"OrderAddressType",
+ "OrderBillingAddress",
+ "OrderBillingAddressJapanType",
+ "OrderBillingAddressType",
"OrderCustomerInfo",
"OrderDisputeLastStatus",
"OrderDownloadFilesItem",
@@ -188,15 +735,26 @@
"OrderPurchasedItemVariantImage",
"OrderPurchasedItemVariantImageFile",
"OrderPurchasedItemVariantImageFileVariantsItem",
+ "OrderShippingAddress",
+ "OrderShippingAddressJapanType",
+ "OrderShippingAddressType",
"OrderStatus",
"OrderTotals",
"OrderTotalsExtrasItem",
"OrderTotalsExtrasItemType",
"Page",
+ "PageCreatedWebhook",
+ "PageCreatedWebhookPayload",
+ "PageDeletedWebhook",
+ "PageDeletedWebhookPayload",
"PageList",
+ "PageMetadataUpdatedWebhook",
+ "PageMetadataUpdatedWebhookPayload",
"PageOpenGraph",
"PageSeo",
"Pagination",
+ "Payload",
+ "PayloadFieldData",
"PaypalDetails",
"Product",
"ProductAndSkUs",
@@ -205,41 +763,106 @@
"ProductFieldDataEcProductType",
"ProductFieldDataTaxCategory",
"PublishStatus",
+ "Redirect",
+ "Redirects",
+ "ReferenceField",
+ "ReferenceFieldMetadata",
+ "ReferenceFieldType",
"RegisteredScriptList",
+ "Robots",
+ "RobotsRulesItem",
"ScriptApply",
"ScriptApplyList",
"ScriptApplyLocation",
"Scripts",
+ "SearchButtonNode",
+ "SearchButtonNodeWrite",
+ "Select",
+ "SelectNode",
+ "SelectNodeChoicesItem",
+ "SelectNodeWriteChoicesItem",
+ "SettingChange",
+ "SettingChangeAuditLogItem",
+ "SingleLocaleCreatedPayload",
+ "SingleLocaleCreatedPayloadFieldData",
"Site",
"SiteActivityLogItem",
+ "SiteActivityLogItemEvent",
"SiteActivityLogItemResourceOperation",
"SiteActivityLogItemUser",
"SiteActivityLogResponse",
+ "SiteDataCollectionType",
+ "SiteMembership",
+ "SiteMembershipAuditLogItem",
+ "SiteMembershipAuditLogItemEventSubType",
+ "SitePlan",
+ "SitePlanId",
+ "SitePlanName",
+ "SitePublish",
+ "SitePublishPayload",
+ "Sites",
"Sku",
"SkuFieldData",
"SkuFieldDataCompareAtPrice",
"SkuFieldDataEcSkuBillingMethod",
"SkuFieldDataEcSkuSubscriptionPlan",
"SkuFieldDataEcSkuSubscriptionPlanInterval",
+ "SkuFieldDataEcSkuSubscriptionPlanPlansItem",
+ "SkuFieldDataEcSkuSubscriptionPlanPlansItemStatus",
"SkuFieldDataPrice",
"SkuPropertyList",
"SkuPropertyListEnumItem",
"SkuValueList",
+ "StaticField",
+ "StaticFieldType",
"StripeCard",
"StripeCardBrand",
"StripeCardExpires",
"StripeDetails",
+ "SubmitButtonNode",
+ "SubmitButtonNodeWrite",
+ "Text",
+ "TextInputNode",
+ "TextInputNodeWrite",
"TextNode",
+ "TextNodeText",
+ "TextNodeWrite",
"TriggerType",
- "User",
- "UserAccessGroupsItem",
- "UserAccessGroupsItemType",
- "UserData",
- "UserDataData",
- "UserLimitReached",
- "UserList",
- "UserStatus",
- "UsersNotEnabled",
+ "UpdatedOrder",
+ "UserAccess",
+ "UserAccessAuditLogItem",
+ "UserAccessAuditLogItemEventSubType",
"Webhook",
+ "WebhookFilter",
"WebhookList",
+ "WorkspaceAuditLogItem",
+ "WorkspaceAuditLogItemActor",
+ "WorkspaceAuditLogItemPayloadSettingChangeMethod",
+ "WorkspaceAuditLogItemPayloadSiteMembershipGranularAccess",
+ "WorkspaceAuditLogItemPayloadSiteMembershipMethod",
+ "WorkspaceAuditLogItemPayloadSiteMembershipSite",
+ "WorkspaceAuditLogItemPayloadSiteMembershipTargetUser",
+ "WorkspaceAuditLogItemPayloadSiteMembershipUserType",
+ "WorkspaceAuditLogItemPayloadUserAccessMethod",
+ "WorkspaceAuditLogItemPayloadWorkspaceInvitationMethod",
+ "WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUser",
+ "WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUsersItem",
+ "WorkspaceAuditLogItemPayloadWorkspaceInvitationUserType",
+ "WorkspaceAuditLogItemPayloadWorkspaceMembershipMethod",
+ "WorkspaceAuditLogItemPayloadWorkspaceMembershipTargetUser",
+ "WorkspaceAuditLogItemPayloadWorkspaceMembershipUserType",
+ "WorkspaceAuditLogItemWorkspace",
+ "WorkspaceAuditLogItem_CustomRole",
+ "WorkspaceAuditLogItem_SiteMembership",
+ "WorkspaceAuditLogItem_UserAccess",
+ "WorkspaceAuditLogItem_WorkspaceInvitation",
+ "WorkspaceAuditLogItem_WorkspaceMembership",
+ "WorkspaceAuditLogItem_WorkspaceSetting",
+ "WorkspaceAuditLogResponse",
+ "WorkspaceInvitation",
+ "WorkspaceInvitationAuditLogItem",
+ "WorkspaceInvitationAuditLogItemEventSubType",
+ "WorkspaceMembership",
+ "WorkspaceMembershipAuditLogItem",
+ "WorkspaceMembershipAuditLogItemEventSubType",
]
diff --git a/src/webflow/types/access_group.py b/src/webflow/types/access_group.py
deleted file mode 100644
index 5e07de0..0000000
--- a/src/webflow/types/access_group.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import datetime as dt
-import typing
-
-from ..core.datetime_utils import serialize_datetime
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class AccessGroup(pydantic.BaseModel):
- id: typing.Optional[str] = pydantic.Field(default=None, description="Unique identifier for the Access Group")
- name: typing.Optional[str] = pydantic.Field(default=None, description="Name of the the Access Group")
- short_id: typing.Optional[str] = pydantic.Field(
- alias="shortId",
- default=None,
- description="Shortened unique identifier based on name, optimized for its use in the user’s JWT",
- )
- slug: typing.Optional[str] = pydantic.Field(
- default=None,
- description="Shortened unique identifier based on name, optimized for human readability and public API use",
- )
- created_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="createdOn", default=None, description="The date the Access Group was created"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
diff --git a/src/webflow/types/access_group_list.py b/src/webflow/types/access_group_list.py
deleted file mode 100644
index aa36c97..0000000
--- a/src/webflow/types/access_group_list.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import datetime as dt
-import typing
-
-from ..core.datetime_utils import serialize_datetime
-from .access_group import AccessGroup
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class AccessGroupList(pydantic.BaseModel):
- """
- The list access groups results
- """
-
- count: typing.Optional[float] = pydantic.Field(default=None, description="Number of access groups returned")
- limit: typing.Optional[float] = pydantic.Field(default=None, description="The limit specified in the request")
- offset: typing.Optional[float] = pydantic.Field(default=None, description="The offset specified for pagination")
- total: typing.Optional[float] = pydantic.Field(
- default=None, description="Total number of access groups in the collection"
- )
- access_groups: typing.Optional[typing.List[AccessGroup]] = pydantic.Field(
- alias="accessGroups", default=None, description="List of Site Access Groups"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
diff --git a/src/webflow/types/application.py b/src/webflow/types/application.py
index bdfe171..2b86757 100644
--- a/src/webflow/types/application.py
+++ b/src/webflow/types/application.py
@@ -2,4 +2,39 @@
import typing
-Application = typing.Any
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+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(alias="displayName", description="Application name provided by the developer"),
+ ] = 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/asset.py b/src/webflow/types/asset.py
index 0d80162..eb3425d 100644
--- a/src/webflow/types/asset.py
+++ b/src/webflow/types/asset.py
@@ -3,49 +3,79 @@
import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .asset_variant import AssetVariant
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class Asset(pydantic.BaseModel):
- id: typing.Optional[str] = pydantic.Field(default=None, description="Unique identifier for this asset")
- content_type: typing.Optional[str] = pydantic.Field(
- alias="contentType", default=None, description="File format type"
- )
- size: typing.Optional[int] = pydantic.Field(default=None, description="size in bytes")
- site_id: typing.Optional[str] = pydantic.Field(
- alias="siteId", default=None, description="Unique identifier for the site that hosts this asset"
- )
- hosted_url: typing.Optional[str] = pydantic.Field(alias="hostedUrl", default=None, description="Link to the asset")
- original_file_name: typing.Optional[str] = pydantic.Field(
- alias="originalFileName", default=None, description="Original file name at the time of upload"
- )
- display_name: typing.Optional[str] = pydantic.Field(
- alias="displayName", default=None, description="Display name of the asset"
- )
- last_updated: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastUpdated", default=None, description="Date the asset metadata was last updated"
- )
- created_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="createdOn", default=None, description="Date the asset metadata was created"
- )
- variants: typing.Optional[typing.List[AssetVariant]] = None
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+
+class Asset(UniversalBaseModel):
+ """
+ Asset details
+ """
+
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Unique identifier for this asset
+ """
+
+ content_type: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="contentType"),
+ pydantic.Field(alias="contentType", description="File format type"),
+ ] = None
+ size: typing.Optional[int] = pydantic.Field(default=None)
+ """
+ size in bytes
+ """
+
+ site_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="siteId"),
+ pydantic.Field(alias="siteId", description="Unique identifier for the site that hosts this asset"),
+ ] = None
+ hosted_url: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="hostedUrl"),
+ pydantic.Field(alias="hostedUrl", description="Link to the asset"),
+ ] = None
+ original_file_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="originalFileName"),
+ pydantic.Field(alias="originalFileName", description="Original file name at the time of upload"),
+ ] = None
+ display_name: typing_extensions.Annotated[
+ str,
+ FieldMetadata(alias="displayName"),
+ pydantic.Field(alias="displayName", description="Display name of the asset"),
+ ]
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="Date the asset metadata was last updated"),
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="Date the asset metadata was created"),
+ ] = 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(alias="altText", description="The visual description of the asset"),
+ ] = 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/asset_folder.py b/src/webflow/types/asset_folder.py
index 130b755..193fd69 100644
--- a/src/webflow/types/asset_folder.py
+++ b/src/webflow/types/asset_folder.py
@@ -3,49 +3,58 @@
import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class AssetFolder(pydantic.BaseModel):
+class AssetFolder(UniversalBaseModel):
"""
Asset Folder details
"""
- display_name: typing.Optional[str] = pydantic.Field(
- alias="displayName", default=None, description="User visible name for the Asset Folder"
- )
- id: typing.Optional[str] = pydantic.Field(default=None, description="Unique identifier for the Asset Folder")
- parent_folder: typing.Optional[str] = pydantic.Field(
- alias="parentFolder", default=None, description="Pointer to parent Asset Folder (or null if root)"
- )
- assets: typing.Optional[typing.List[str]] = pydantic.Field(
- default=None, description="Array of Asset instances in the folder"
- )
- site_id: typing.Optional[str] = pydantic.Field(
- alias="siteId", default=None, description="The unique id of the site the Asset Folder belongs to"
- )
- created_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="createdOn", default=None, description="Date that the Asset Folder was created on"
- )
- last_updated: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastUpdated", default=None, description="Date that the Asset Folder was last updated on"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Unique identifier for the Asset Folder
+ """
+
+ display_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="displayName"),
+ pydantic.Field(alias="displayName", description="User visible name for the Asset Folder"),
+ ] = None
+ parent_folder: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="parentFolder"),
+ pydantic.Field(alias="parentFolder", description="Pointer to parent Asset Folder (or null if root)"),
+ ] = None
+ assets: typing.Optional[typing.List[str]] = pydantic.Field(default=None)
+ """
+ Array of Asset instances in the folder
+ """
+
+ site_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="siteId"),
+ pydantic.Field(alias="siteId", description="The unique ID of the site the Asset Folder belongs to"),
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="Date that the Asset Folder was created on"),
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="Date that the Asset Folder was last updated on"),
+ ] = 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/asset_folder_list.py b/src/webflow/types/asset_folder_list.py
index 89e533d..e36db60 100644
--- a/src/webflow/types/asset_folder_list.py
+++ b/src/webflow/types/asset_folder_list.py
@@ -1,38 +1,32 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .asset_folder import AssetFolder
from .pagination import Pagination
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class AssetFolderList(pydantic.BaseModel):
+class AssetFolderList(UniversalBaseModel):
"""
The Asset Folders object
"""
- asset_folders: typing.Optional[typing.List[AssetFolder]] = pydantic.Field(
- alias="assetFolders", default=None, description="A list of Asset folders"
- )
+ asset_folders: typing_extensions.Annotated[
+ typing.Optional[typing.List[AssetFolder]],
+ FieldMetadata(alias="assetFolders"),
+ pydantic.Field(alias="assetFolders", description="A list of Asset folders"),
+ ] = None
pagination: typing.Optional[Pagination] = None
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/asset_upload.py b/src/webflow/types/asset_upload.py
index 299f032..3f02db2 100644
--- a/src/webflow/types/asset_upload.py
+++ b/src/webflow/types/asset_upload.py
@@ -3,51 +3,65 @@
import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .asset_upload_upload_details import AssetUploadUploadDetails
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class AssetUpload(pydantic.BaseModel):
- upload_details: typing.Optional[AssetUploadUploadDetails] = pydantic.Field(
- alias="uploadDetails", default=None, description="Metadata for uploading the asset binary"
- )
+class AssetUpload(UniversalBaseModel):
+ upload_details: typing_extensions.Annotated[
+ typing.Optional[AssetUploadUploadDetails],
+ FieldMetadata(alias="uploadDetails"),
+ pydantic.Field(alias="uploadDetails", description="Metadata for uploading the asset binary"),
+ ] = None
+ content_type: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="contentType"), pydantic.Field(alias="contentType")
+ ] = None
id: typing.Optional[str] = None
- content_type: typing.Optional[str] = pydantic.Field(alias="contentType", default=None)
- parent_folder: typing.Optional[str] = pydantic.Field(
- alias="parentFolder", default=None, description="Parent folder for the asset"
- )
- hosted_url: typing.Optional[str] = pydantic.Field(
- alias="hostedUrl", default=None, description="Represents the link to the asset"
- )
- upload_url: typing.Optional[str] = pydantic.Field(alias="uploadUrl", default=None)
- asset_url: typing.Optional[str] = pydantic.Field(alias="assetUrl", default=None, description="S3 link to the asset")
- original_file_name: typing.Optional[str] = pydantic.Field(
- alias="originalFileName",
- default=None,
- description="Original file name when uploaded. If not specified at time of upload, it may be extracted from the raw file name",
- )
- last_updated: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastUpdated", default=None, description="Date the asset metadata was last updated"
- )
- created_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="createdOn", default=None, description="Date the asset metadata was created"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ parent_folder: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="parentFolder"),
+ pydantic.Field(alias="parentFolder", description="Parent folder for the asset"),
+ ] = None
+ upload_url: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="uploadUrl"), pydantic.Field(alias="uploadUrl")
+ ] = None
+ asset_url: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="assetUrl"),
+ pydantic.Field(alias="assetUrl", description="S3 link to the asset"),
+ ] = None
+ hosted_url: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="hostedUrl"),
+ pydantic.Field(alias="hostedUrl", description="Represents the link to the asset"),
+ ] = None
+ original_file_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="originalFileName"),
+ pydantic.Field(
+ alias="originalFileName",
+ description="Original file name when uploaded. If not specified at time of upload, it may be extracted from the raw file name",
+ ),
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="Date the asset metadata was created"),
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="Date the asset metadata was last updated"),
+ ] = None
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/asset_upload_upload_details.py b/src/webflow/types/asset_upload_upload_details.py
index 244ad84..68e174e 100644
--- a/src/webflow/types/asset_upload_upload_details.py
+++ b/src/webflow/types/asset_upload_upload_details.py
@@ -1,48 +1,49 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class AssetUploadUploadDetails(pydantic.BaseModel):
+class AssetUploadUploadDetails(UniversalBaseModel):
"""
Metadata for uploading the asset binary
"""
acl: typing.Optional[str] = None
bucket: typing.Optional[str] = None
+ x_amz_algorithm: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="X-Amz-Algorithm"), pydantic.Field(alias="X-Amz-Algorithm")
+ ] = None
+ x_amz_credential: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="X-Amz-Credential"), pydantic.Field(alias="X-Amz-Credential")
+ ] = None
+ x_amz_date: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="X-Amz-Date"), pydantic.Field(alias="X-Amz-Date")
+ ] = None
key: typing.Optional[str] = None
- policy: typing.Optional[str] = pydantic.Field(alias="Policy", default=None)
- x_amz_algorithm: typing.Optional[str] = pydantic.Field(alias="X-Amz-Algorithm", default=None)
- x_amz_credential: typing.Optional[str] = pydantic.Field(alias="X-Amz-Credential", default=None)
- x_amz_date: typing.Optional[str] = pydantic.Field(alias="X-Amz-Date", default=None)
- x_amz_security_token: typing.Optional[str] = pydantic.Field(
- alias="X-Amz-Security-Token",
- default=None,
- description="(optional) Temporary security token obtained when authenticated through AWS STS",
- )
- x_amz_signature: typing.Optional[str] = pydantic.Field(alias="X-Amz-Signature", default=None)
+ policy: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="Policy"), pydantic.Field(alias="Policy")
+ ] = None
+ x_amz_signature: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="X-Amz-Signature"), pydantic.Field(alias="X-Amz-Signature")
+ ] = None
success_action_status: typing.Optional[str] = None
- content_type: typing.Optional[str] = pydantic.Field(alias="content-type", default=None)
- cache_control: typing.Optional[str] = pydantic.Field(alias="Cache-Control", default=None)
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ content_type: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="content-type"), pydantic.Field(alias="content-type")
+ ] = None
+ cache_control: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="Cache-Control"), pydantic.Field(alias="Cache-Control")
+ ] = 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/asset_variant.py b/src/webflow/types/asset_variant.py
index 00af16a..f43472d 100644
--- a/src/webflow/types/asset_variant.py
+++ b/src/webflow/types/asset_variant.py
@@ -1,38 +1,63 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class AssetVariant(pydantic.BaseModel):
- hosted_url: typing.Optional[str] = pydantic.Field(alias="hostedUrl", default=None)
- original_file_name: typing.Optional[str] = pydantic.Field(alias="originalFileName", default=None)
- display_name: typing.Optional[str] = pydantic.Field(alias="displayName", default=None)
- format: typing.Optional[str] = None
- width: typing.Optional[int] = pydantic.Field(default=None, description="Width in pixels")
- height: typing.Optional[int] = pydantic.Field(default=None, description="Height in pixels")
- quality: typing.Optional[int] = pydantic.Field(
- default=None, description="Value between 0 and 100 representing the image quality"
- )
- error: typing.Optional[str] = pydantic.Field(default=None, description="Any associated validation errors")
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class AssetVariant(UniversalBaseModel):
+ """
+ Asset variant details
+ """
+
+ hosted_url: typing_extensions.Annotated[
+ str,
+ FieldMetadata(alias="hostedUrl"),
+ pydantic.Field(alias="hostedUrl", description="URL of where the asset variant is hosted"),
+ ]
+ original_file_name: typing_extensions.Annotated[
+ str,
+ FieldMetadata(alias="originalFileName"),
+ pydantic.Field(alias="originalFileName", description="Original file name of the variant"),
+ ]
+ display_name: typing_extensions.Annotated[
+ str,
+ FieldMetadata(alias="displayName"),
+ pydantic.Field(alias="displayName", description="Display name of the variant"),
+ ]
+ format: str = pydantic.Field()
+ """
+ format of the variant
+ """
+
+ width: int = pydantic.Field()
+ """
+ Width in pixels
+ """
+
+ height: typing.Optional[int] = pydantic.Field(default=None)
+ """
+ Height in pixels
+ """
+
+ quality: int = pydantic.Field()
+ """
+ Value between 0 and 100 representing the image quality
+ """
+
+ error: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Any associated validation errors
+ """
+
+ 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/assets.py b/src/webflow/types/assets.py
index 3b1ee70..ed33272 100644
--- a/src/webflow/types/assets.py
+++ b/src/webflow/types/assets.py
@@ -1,33 +1,26 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from .asset import Asset
+from .pagination import Pagination
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class Assets(pydantic.BaseModel):
+class Assets(UniversalBaseModel):
"""
A list of assets
"""
assets: typing.Optional[typing.List[Asset]] = None
+ pagination: typing.Optional[Pagination] = None
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/authorization.py b/src/webflow/types/authorization.py
index c896ac6..6deea56 100644
--- a/src/webflow/types/authorization.py
+++ b/src/webflow/types/authorization.py
@@ -1,33 +1,26 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from .application import Application
from .authorization_authorization import AuthorizationAuthorization
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+class Authorization(UniversalBaseModel):
+ authorization: typing.Optional[AuthorizationAuthorization] = pydantic.Field(default=None)
+ """
+ The Authorization object
+ """
-class Authorization(pydantic.BaseModel):
- authorization: typing.Optional[AuthorizationAuthorization] = pydantic.Field(
- default=None, description="The Authorization object"
- )
application: typing.Optional[Application] = None
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/authorization_authorization.py b/src/webflow/types/authorization_authorization.py
index cb2780e..e3ee7ca 100644
--- a/src/webflow/types/authorization_authorization.py
+++ b/src/webflow/types/authorization_authorization.py
@@ -3,50 +3,59 @@
import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .authorization_authorization_authorized_to import AuthorizationAuthorizationAuthorizedTo
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class AuthorizationAuthorization(pydantic.BaseModel):
+class AuthorizationAuthorization(UniversalBaseModel):
"""
The Authorization object
"""
- id: typing.Optional[str] = pydantic.Field(default=None, description="The unique id of the Authorization instance")
- created_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="createdOn", default=None, description="The date the Authorization was created"
- )
- last_used: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastUsed", default=None, description="The date the Authorization was last used"
- )
- grant_type: typing.Optional[str] = pydantic.Field(
- alias="grantType", default=None, description="The grant type of the Authorization"
- )
- rate_limit: typing.Optional[int] = pydantic.Field(
- alias="rateLimit", default=None, description="The default rate limit for the Authorization (requests/min)"
- )
- scope: typing.Optional[str] = pydantic.Field(
- default=None, description="Comma separted list of OAuth scopes corresponding to the Authorization"
- )
- authorized_to: typing.Optional[AuthorizationAuthorizationAuthorizedTo] = pydantic.Field(
- alias="authorizedTo", default=None
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The unique ID of the Authorization instance
+ """
+
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="The date the Authorization was created"),
+ ] = None
+ last_used: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="lastUsed"),
+ pydantic.Field(alias="lastUsed", description="The date the Authorization was last used"),
+ ] = None
+ grant_type: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="grantType"),
+ pydantic.Field(alias="grantType", description="The grant type of the Authorization"),
+ ] = None
+ rate_limit: typing_extensions.Annotated[
+ typing.Optional[int],
+ FieldMetadata(alias="rateLimit"),
+ pydantic.Field(alias="rateLimit", description="The default rate limit for the Authorization (requests/min)"),
+ ] = None
+ scope: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Comma separted list of OAuth scopes corresponding to the Authorization
+ """
+
+ authorized_to: typing_extensions.Annotated[
+ typing.Optional[AuthorizationAuthorizationAuthorizedTo],
+ FieldMetadata(alias="authorizedTo"),
+ pydantic.Field(alias="authorizedTo"),
+ ] = 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/authorization_authorization_authorized_to.py b/src/webflow/types/authorization_authorization_authorized_to.py
index e80f490..d0189e4 100644
--- a/src/webflow/types/authorization_authorization_authorized_to.py
+++ b/src/webflow/types/authorization_authorization_authorized_to.py
@@ -1,37 +1,35 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class AuthorizationAuthorizationAuthorizedTo(pydantic.BaseModel):
- site_ids: typing.Optional[typing.List[typing.Any]] = pydantic.Field(
- alias="siteIds", default=None, description="Array of Sites this app is authorized to"
- )
- workspace_ids: typing.Optional[typing.List[typing.Any]] = pydantic.Field(
- alias="workspaceIds", default=None, description="Array of Workspaces this app is authorized to"
- )
- user_ids: typing.Optional[typing.List[typing.Any]] = pydantic.Field(
- alias="userIds", default=None, description="Array of Users this app is authorized to"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class AuthorizationAuthorizationAuthorizedTo(UniversalBaseModel):
+ site_ids: typing_extensions.Annotated[
+ typing.Optional[typing.List[typing.Any]],
+ FieldMetadata(alias="siteIds"),
+ pydantic.Field(alias="siteIds", description="Array of Sites this app is authorized to"),
+ ] = None
+ workspace_ids: typing_extensions.Annotated[
+ typing.Optional[typing.List[typing.Any]],
+ FieldMetadata(alias="workspaceIds"),
+ pydantic.Field(alias="workspaceIds", description="Array of Workspaces this app is authorized to"),
+ ] = None
+ user_ids: typing_extensions.Annotated[
+ typing.Optional[typing.List[typing.Any]],
+ FieldMetadata(alias="userIds"),
+ pydantic.Field(alias="userIds", description="Array of Users this app is authorized to"),
+ ] = 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/authorized_user.py b/src/webflow/types/authorized_user.py
index 8f754d3..bbbb058 100644
--- a/src/webflow/types/authorized_user.py
+++ b/src/webflow/types/authorized_user.py
@@ -1,34 +1,40 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class AuthorizedUser(pydantic.BaseModel):
- id: typing.Optional[str] = pydantic.Field(default=None, description="The unique id of the user")
- email: typing.Optional[str] = pydantic.Field(default=None, description="The user's email address")
- first_name: typing.Optional[str] = pydantic.Field(
- alias="firstName", default=None, description="The user's first name"
- )
- last_name: typing.Optional[str] = pydantic.Field(alias="lastName", default=None, description="The user's last name")
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class AuthorizedUser(UniversalBaseModel):
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The unique ID of the user
+ """
+
+ email: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The user's email address
+ """
+
+ first_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="firstName"),
+ pydantic.Field(alias="firstName", description="The user's first name"),
+ ] = None
+ last_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="lastName"),
+ pydantic.Field(alias="lastName", description="The user's last name"),
+ ] = 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/bad_request_error_body.py b/src/webflow/types/bad_request_error_body.py
new file mode 100644
index 0000000..6403cc4
--- /dev/null
+++ b/src/webflow/types/bad_request_error_body.py
@@ -0,0 +1,8 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from .invalid_domain import InvalidDomain
+from .no_domains import NoDomains
+
+BadRequestErrorBody = typing.Union[InvalidDomain, NoDomains]
diff --git a/src/webflow/types/bulk_collection_item.py b/src/webflow/types/bulk_collection_item.py
new file mode 100644
index 0000000..f53e06d
--- /dev/null
+++ b/src/webflow/types/bulk_collection_item.py
@@ -0,0 +1,67 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .bulk_collection_item_field_data import BulkCollectionItemFieldData
+
+
+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: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Unique identifier for the Item
+ """
+
+ cms_locale_ids: typing_extensions.Annotated[
+ typing.Optional[typing.List[str]],
+ FieldMetadata(alias="cmsLocaleIds"),
+ pydantic.Field(
+ alias="cmsLocaleIds", description="Array of identifiers for the locales where the item will be created"
+ ),
+ ] = None
+ last_published: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="lastPublished"),
+ pydantic.Field(alias="lastPublished", description="The date the item was last published"),
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="The date the item was last updated"),
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="The date the item was created"),
+ ] = None
+ is_archived: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="isArchived"),
+ pydantic.Field(alias="isArchived", description="Boolean determining if the Item is set to archived"),
+ ] = None
+ is_draft: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="isDraft"),
+ pydantic.Field(alias="isDraft", description="Boolean determining if the Item is set to draft"),
+ ] = None
+ field_data: typing_extensions.Annotated[
+ typing.Optional[BulkCollectionItemFieldData],
+ FieldMetadata(alias="fieldData"),
+ pydantic.Field(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/types/bulk_collection_item_field_data.py b/src/webflow/types/bulk_collection_item_field_data.py
new file mode 100644
index 0000000..f428233
--- /dev/null
+++ b/src/webflow/types/bulk_collection_item_field_data.py
@@ -0,0 +1,27 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class BulkCollectionItemFieldData(UniversalBaseModel):
+ name: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Name of the Item
+ """
+
+ slug: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ URL structure of the Item in your site. Note: Updates to an item slug will break all links referencing the old slug.
+ """
+
+ 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/collection.py b/src/webflow/types/collection.py
index 6887a61..1976f76 100644
--- a/src/webflow/types/collection.py
+++ b/src/webflow/types/collection.py
@@ -3,47 +3,61 @@
import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .field import Field
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class Collection(pydantic.BaseModel):
+class Collection(UniversalBaseModel):
"""
A collection object
"""
- id: str = pydantic.Field(description="Unique identifier for a Collection")
- display_name: typing.Optional[str] = pydantic.Field(
- alias="displayName", default=None, description="Name given to the Collection"
- )
- singular_name: typing.Optional[str] = pydantic.Field(
- alias="singularName",
- default=None,
- description="The name of one Item in Collection (e.g. ”Blog Post” if the Collection is called “Blog Posts”)",
- )
- slug: typing.Optional[str] = pydantic.Field(default=None, description="Slug of Collection in Site URL structure")
- created_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="createdOn", default=None, description="The date the collection was created"
- )
- last_updated: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastUpdated", default=None, description="The date the collection was last updated"
- )
- fields: typing.Dict[str, typing.Any] = pydantic.Field(description="The list of fields in the Collection")
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ id: str = pydantic.Field()
+ """
+ Unique identifier for a Collection
+ """
+
+ display_name: typing_extensions.Annotated[
+ str,
+ FieldMetadata(alias="displayName"),
+ pydantic.Field(alias="displayName", description="Name given to the Collection"),
+ ]
+ singular_name: typing_extensions.Annotated[
+ str,
+ FieldMetadata(alias="singularName"),
+ pydantic.Field(
+ alias="singularName",
+ description="The name of one Item in Collection (e.g. ”Blog Post” if the Collection is called “Blog Posts”)",
+ ),
+ ]
+ slug: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Slug of Collection in Site URL structure
+ """
+
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="The date the collection was created"),
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="The date the collection was last updated"),
+ ] = None
+ fields: typing.List[Field] = pydantic.Field()
+ """
+ The list of fields in 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/collection_item.py b/src/webflow/types/collection_item.py
index 82a0629..832a11c 100644
--- a/src/webflow/types/collection_item.py
+++ b/src/webflow/types/collection_item.py
@@ -1,53 +1,67 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .collection_item_field_data import CollectionItemFieldData
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+class CollectionItem(UniversalBaseModel):
+ """
+ A Collection Item represents a single entry in your collection. Each item includes:
+
+ - **System metadata** - Automatically managed fields like IDs and timestamp
+ - **Status flags** - Controls for managing content state: `isDraft`, `isArchived `
+ - **Content fields** - Stored in `fieldData`. Each item needs a `name` and `slug`, and may include additional fields matching your collection's schema definition.
+ """
-class CollectionItem(pydantic.BaseModel):
+ id: typing.Optional[str] = pydantic.Field(default=None)
"""
- 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
+ Unique identifier for the Item
"""
- id: str = pydantic.Field(description="Unique identifier for the Item")
- cms_locale_id: typing.Optional[str] = pydantic.Field(
- alias="cmsLocaleId", default=None, description="Identifier for the locale of the CMS item"
- )
- last_published: typing.Optional[str] = pydantic.Field(
- alias="lastPublished", default=None, description="The date the item was last published"
- )
- last_updated: typing.Optional[str] = pydantic.Field(
- alias="lastUpdated", default=None, description="The date the item was last updated"
- )
- created_on: typing.Optional[str] = pydantic.Field(
- alias="createdOn", default=None, description="The date the item was created"
- )
- is_archived: typing.Optional[bool] = pydantic.Field(
- alias="isArchived", default=None, description="Boolean determining if the Item is set to archived"
- )
- is_draft: typing.Optional[bool] = pydantic.Field(
- alias="isDraft", default=None, description="Boolean determining if the Item is set to draft"
- )
- field_data: typing.Optional[CollectionItemFieldData] = pydantic.Field(alias="fieldData", default=None)
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ cms_locale_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="cmsLocaleId"),
+ pydantic.Field(alias="cmsLocaleId", description="Identifier for the locale of the CMS item"),
+ ] = None
+ last_published: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="lastPublished"),
+ pydantic.Field(alias="lastPublished", description="The date the item was last published"),
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="The date the item was last updated"),
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="The date the item was created"),
+ ] = None
+ is_archived: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="isArchived"),
+ pydantic.Field(alias="isArchived", description="Boolean determining if the Item is set to archived"),
+ ] = None
+ is_draft: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="isDraft"),
+ pydantic.Field(alias="isDraft", description="Boolean determining if the Item is set to draft"),
+ ] = None
+ field_data: typing_extensions.Annotated[
+ CollectionItemFieldData, FieldMetadata(alias="fieldData"), pydantic.Field(alias="fieldData")
+ ]
+
+ 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/collection_item_changed.py b/src/webflow/types/collection_item_changed.py
new file mode 100644
index 0000000..2586381
--- /dev/null
+++ b/src/webflow/types/collection_item_changed.py
@@ -0,0 +1,31 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .single_locale_created_payload import SingleLocaleCreatedPayload
+
+
+class CollectionItemChanged(UniversalBaseModel):
+ """
+ The Webhook payload for when a Collection Item is changed
+ """
+
+ trigger_type: typing_extensions.Annotated[
+ typing.Literal["collection_item_changed"],
+ FieldMetadata(alias="triggerType"),
+ pydantic.Field(alias="triggerType", description="The type of event that triggered the request"),
+ ] = "collection_item_changed"
+ payload: SingleLocaleCreatedPayload
+
+ 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/collection_item_created.py b/src/webflow/types/collection_item_created.py
new file mode 100644
index 0000000..0103ed7
--- /dev/null
+++ b/src/webflow/types/collection_item_created.py
@@ -0,0 +1,31 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .single_locale_created_payload import SingleLocaleCreatedPayload
+
+
+class CollectionItemCreated(UniversalBaseModel):
+ """
+ The Webhook payload for when a Collection Item is created
+ """
+
+ trigger_type: typing_extensions.Annotated[
+ typing.Literal["collection_item_created"],
+ FieldMetadata(alias="triggerType"),
+ pydantic.Field(alias="triggerType", description="The type of event that triggered the request"),
+ ] = "collection_item_created"
+ payload: SingleLocaleCreatedPayload
+
+ 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/collection_item_field_data.py b/src/webflow/types/collection_item_field_data.py
index ba2c2fc..f531e2e 100644
--- a/src/webflow/types/collection_item_field_data.py
+++ b/src/webflow/types/collection_item_field_data.py
@@ -1,32 +1,27 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+class CollectionItemFieldData(UniversalBaseModel):
+ name: str = pydantic.Field()
+ """
+ Name of the Item
+ """
-class CollectionItemFieldData(pydantic.BaseModel):
- name: typing.Optional[str] = pydantic.Field(default=None, description="Name of the Item")
- slug: typing.Optional[str] = pydantic.Field(
- default=None,
- description="URL structure of the Item in your site. Note: Updates to an item slug will break all links referencing the old slug.",
- )
+ slug: str = pydantic.Field()
+ """
+ URL structure of the Item in your site. Note: Updates to an item slug will break all links referencing the old slug.
+ """
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/collection_item_list.py b/src/webflow/types/collection_item_list.py
index 11f519c..ee576c5 100644
--- a/src/webflow/types/collection_item_list.py
+++ b/src/webflow/types/collection_item_list.py
@@ -1,37 +1,30 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from .collection_item import CollectionItem
from .collection_item_list_pagination import CollectionItemListPagination
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class CollectionItemList(pydantic.BaseModel):
+class CollectionItemList(UniversalBaseModel):
"""
Results from collection items list
"""
- items: typing.Optional[typing.List[CollectionItem]] = pydantic.Field(
- default=None, description="List of Items within the collection"
- )
- pagination: typing.Optional[CollectionItemListPagination] = None
+ items: typing.Optional[typing.List[CollectionItem]] = pydantic.Field(default=None)
+ """
+ List of Items within the collection
+ """
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ pagination: typing.Optional[CollectionItemListPagination] = None
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/collection_item_list_no_pagination.py b/src/webflow/types/collection_item_list_no_pagination.py
new file mode 100644
index 0000000..bdd0bcd
--- /dev/null
+++ b/src/webflow/types/collection_item_list_no_pagination.py
@@ -0,0 +1,27 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .collection_item import CollectionItem
+
+
+class CollectionItemListNoPagination(UniversalBaseModel):
+ """
+ Results from collection items list
+ """
+
+ items: typing.Optional[typing.List[CollectionItem]] = pydantic.Field(default=None)
+ """
+ List of Items within 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/collection_item_list_pagination.py b/src/webflow/types/collection_item_list_pagination.py
index ffb4c77..a8f72be 100644
--- a/src/webflow/types/collection_item_list_pagination.py
+++ b/src/webflow/types/collection_item_list_pagination.py
@@ -1,30 +1,32 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+class CollectionItemListPagination(UniversalBaseModel):
+ limit: typing.Optional[int] = pydantic.Field(default=None)
+ """
+ The limit specified in the request
+ """
-class CollectionItemListPagination(pydantic.BaseModel):
- limit: typing.Optional[float] = pydantic.Field(default=None, description="The limit specified in the request")
- offset: typing.Optional[float] = pydantic.Field(default=None, description="The offset specified for pagination")
- total: typing.Optional[float] = pydantic.Field(default=None, description="Total number of items in the collection")
+ offset: typing.Optional[int] = pydantic.Field(default=None)
+ """
+ The offset specified for pagination
+ """
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ total: typing.Optional[int] = pydantic.Field(default=None)
+ """
+ Total number of items in the collection
+ """
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/collection_item_patch_single.py b/src/webflow/types/collection_item_patch_single.py
new file mode 100644
index 0000000..64b0170
--- /dev/null
+++ b/src/webflow/types/collection_item_patch_single.py
@@ -0,0 +1,65 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .collection_item_patch_single_field_data import CollectionItemPatchSingleFieldData
+
+
+class CollectionItemPatchSingle(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: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Unique identifier for the Item
+ """
+
+ cms_locale_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="cmsLocaleId"),
+ pydantic.Field(alias="cmsLocaleId", description="Identifier for the locale of the CMS item"),
+ ] = None
+ last_published: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="lastPublished"),
+ pydantic.Field(alias="lastPublished", description="The date the item was last published"),
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="The date the item was last updated"),
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="The date the item was created"),
+ ] = None
+ is_archived: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="isArchived"),
+ pydantic.Field(alias="isArchived", description="Boolean determining if the Item is set to archived"),
+ ] = None
+ is_draft: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="isDraft"),
+ pydantic.Field(alias="isDraft", description="Boolean determining if the Item is set to draft"),
+ ] = None
+ field_data: typing_extensions.Annotated[
+ typing.Optional[CollectionItemPatchSingleFieldData],
+ FieldMetadata(alias="fieldData"),
+ pydantic.Field(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/types/collection_item_patch_single_field_data.py b/src/webflow/types/collection_item_patch_single_field_data.py
new file mode 100644
index 0000000..f952564
--- /dev/null
+++ b/src/webflow/types/collection_item_patch_single_field_data.py
@@ -0,0 +1,27 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class CollectionItemPatchSingleFieldData(UniversalBaseModel):
+ name: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Name of the Item
+ """
+
+ slug: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ URL structure of the Item in your site. Note: Updates to an item slug will break all links referencing the old slug.
+ """
+
+ 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/collection_item_post_single.py b/src/webflow/types/collection_item_post_single.py
new file mode 100644
index 0000000..f58465a
--- /dev/null
+++ b/src/webflow/types/collection_item_post_single.py
@@ -0,0 +1,67 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .collection_item_post_single_field_data import CollectionItemPostSingleFieldData
+
+
+class CollectionItemPostSingle(UniversalBaseModel):
+ """
+ A Collection Item represents a single entry in your collection. Each item includes:
+
+ - **System metadata** - Automatically managed fields like IDs and timestamp
+ - **Status flags** - Controls for managing content state: `isDraft`, `isArchived `
+ - **Content fields** - Stored in `fieldData`. Each item needs a `name` and `slug`, and may include additional fields matching your collection's schema definition.
+ """
+
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Unique identifier for the Item
+ """
+
+ cms_locale_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="cmsLocaleId"),
+ pydantic.Field(alias="cmsLocaleId", description="Identifier for the locale of the CMS item"),
+ ] = None
+ last_published: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="lastPublished"),
+ pydantic.Field(alias="lastPublished", description="The date the item was last published"),
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="The date the item was last updated"),
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="The date the item was created"),
+ ] = None
+ is_archived: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="isArchived"),
+ pydantic.Field(alias="isArchived", description="Boolean determining if the Item is in an archived state."),
+ ] = None
+ is_draft: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="isDraft"),
+ pydantic.Field(alias="isDraft", description="Boolean determining if the Item is in a draft state."),
+ ] = None
+ field_data: typing_extensions.Annotated[
+ CollectionItemPostSingleFieldData, FieldMetadata(alias="fieldData"), pydantic.Field(alias="fieldData")
+ ]
+
+ 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/collection_item_post_single_field_data.py b/src/webflow/types/collection_item_post_single_field_data.py
new file mode 100644
index 0000000..ba4d35a
--- /dev/null
+++ b/src/webflow/types/collection_item_post_single_field_data.py
@@ -0,0 +1,27 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class CollectionItemPostSingleFieldData(UniversalBaseModel):
+ name: str = pydantic.Field()
+ """
+ Name of the Item
+ """
+
+ slug: str = pydantic.Field()
+ """
+ URL structure of the Item in your site. Note: Updates to an item slug will break all links referencing the old slug.
+ """
+
+ 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/collection_item_published.py b/src/webflow/types/collection_item_published.py
new file mode 100644
index 0000000..1b9acc0
--- /dev/null
+++ b/src/webflow/types/collection_item_published.py
@@ -0,0 +1,27 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .payload import Payload
+
+
+class CollectionItemPublished(UniversalBaseModel):
+ trigger_type: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="triggerType"),
+ pydantic.Field(alias="triggerType", description="The type of event that triggered the request"),
+ ] = None
+ payload: typing.Optional[Payload] = 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/collection_item_removed.py b/src/webflow/types/collection_item_removed.py
new file mode 100644
index 0000000..5c2af06
--- /dev/null
+++ b/src/webflow/types/collection_item_removed.py
@@ -0,0 +1,30 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .collection_item_removed_payload import CollectionItemRemovedPayload
+
+
+class CollectionItemRemoved(UniversalBaseModel):
+ trigger_type: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="triggerType"),
+ pydantic.Field(alias="triggerType", description="The type of event that triggered the request"),
+ ] = None
+ payload: typing.Optional[CollectionItemRemovedPayload] = pydantic.Field(default=None)
+ """
+ The payload of data sent from Webflow
+ """
+
+ 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/collection_item_removed_payload.py b/src/webflow/types/collection_item_removed_payload.py
new file mode 100644
index 0000000..011fb89
--- /dev/null
+++ b/src/webflow/types/collection_item_removed_payload.py
@@ -0,0 +1,71 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .collection_item_removed_payload_field_data import CollectionItemRemovedPayloadFieldData
+
+
+class CollectionItemRemovedPayload(UniversalBaseModel):
+ """
+ The payload of data sent from Webflow
+ """
+
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The ID of the collection item that was deleted
+ """
+
+ site_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="siteId"),
+ pydantic.Field(alias="siteId", description="The ID of the site"),
+ ] = None
+ workspace_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="workspaceId"),
+ pydantic.Field(alias="workspaceId", description="The ID of the workspace"),
+ ] = None
+ collection_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="collectionId"),
+ pydantic.Field(alias="collectionId", description="The ID of the collection"),
+ ] = None
+ cms_locale_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="cmsLocaleId"),
+ pydantic.Field(alias="cmsLocaleId", description="Unique identifier of the CMS locale for this item"),
+ ] = None
+ last_published: typing_extensions.Annotated[
+ typing.Optional[dt.datetime], FieldMetadata(alias="lastPublished"), pydantic.Field(alias="lastPublished")
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[dt.datetime], FieldMetadata(alias="lastUpdated"), pydantic.Field(alias="lastUpdated")
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime], FieldMetadata(alias="createdOn"), pydantic.Field(alias="createdOn")
+ ] = None
+ is_archived: typing_extensions.Annotated[
+ typing.Optional[bool], FieldMetadata(alias="isArchived"), pydantic.Field(alias="isArchived")
+ ] = None
+ is_draft: typing_extensions.Annotated[
+ typing.Optional[bool], FieldMetadata(alias="isDraft"), pydantic.Field(alias="isDraft")
+ ] = None
+ field_data: typing_extensions.Annotated[
+ typing.Optional[CollectionItemRemovedPayloadFieldData],
+ FieldMetadata(alias="fieldData"),
+ pydantic.Field(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/types/collection_item_removed_payload_field_data.py b/src/webflow/types/collection_item_removed_payload_field_data.py
new file mode 100644
index 0000000..048baf4
--- /dev/null
+++ b/src/webflow/types/collection_item_removed_payload_field_data.py
@@ -0,0 +1,20 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class CollectionItemRemovedPayloadFieldData(UniversalBaseModel):
+ name: str
+ slug: str
+
+ 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/collection_item_unpublished.py b/src/webflow/types/collection_item_unpublished.py
new file mode 100644
index 0000000..a9200be
--- /dev/null
+++ b/src/webflow/types/collection_item_unpublished.py
@@ -0,0 +1,30 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .collection_item_unpublished_payload import CollectionItemUnpublishedPayload
+
+
+class CollectionItemUnpublished(UniversalBaseModel):
+ trigger_type: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="triggerType"),
+ pydantic.Field(alias="triggerType", description="The type of event that triggered the request"),
+ ] = None
+ payload: typing.Optional[CollectionItemUnpublishedPayload] = pydantic.Field(default=None)
+ """
+ The payload of data sent from Webflow
+ """
+
+ 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/collection_item_unpublished_payload.py b/src/webflow/types/collection_item_unpublished_payload.py
new file mode 100644
index 0000000..2867a45
--- /dev/null
+++ b/src/webflow/types/collection_item_unpublished_payload.py
@@ -0,0 +1,71 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .collection_item_unpublished_payload_field_data import CollectionItemUnpublishedPayloadFieldData
+
+
+class CollectionItemUnpublishedPayload(UniversalBaseModel):
+ """
+ The payload of data sent from Webflow
+ """
+
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The ID of the collection item that was unpublished
+ """
+
+ site_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="siteId"),
+ pydantic.Field(alias="siteId", description="The ID of the site"),
+ ] = None
+ workspace_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="workspaceId"),
+ pydantic.Field(alias="workspaceId", description="The ID of the workspace"),
+ ] = None
+ collection_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="collectionId"),
+ pydantic.Field(alias="collectionId", description="The ID of the collection"),
+ ] = None
+ cms_locale_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="cmsLocaleId"),
+ pydantic.Field(alias="cmsLocaleId", description="Unique identifier of the CMS locale for this item"),
+ ] = None
+ last_published: typing_extensions.Annotated[
+ typing.Optional[dt.datetime], FieldMetadata(alias="lastPublished"), pydantic.Field(alias="lastPublished")
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[dt.datetime], FieldMetadata(alias="lastUpdated"), pydantic.Field(alias="lastUpdated")
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime], FieldMetadata(alias="createdOn"), pydantic.Field(alias="createdOn")
+ ] = None
+ is_archived: typing_extensions.Annotated[
+ typing.Optional[bool], FieldMetadata(alias="isArchived"), pydantic.Field(alias="isArchived")
+ ] = None
+ is_draft: typing_extensions.Annotated[
+ typing.Optional[bool], FieldMetadata(alias="isDraft"), pydantic.Field(alias="isDraft")
+ ] = None
+ field_data: typing_extensions.Annotated[
+ typing.Optional[CollectionItemUnpublishedPayloadFieldData],
+ FieldMetadata(alias="fieldData"),
+ pydantic.Field(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/types/collection_item_unpublished_payload_field_data.py b/src/webflow/types/collection_item_unpublished_payload_field_data.py
new file mode 100644
index 0000000..a2004c1
--- /dev/null
+++ b/src/webflow/types/collection_item_unpublished_payload_field_data.py
@@ -0,0 +1,20 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class CollectionItemUnpublishedPayloadFieldData(UniversalBaseModel):
+ name: str
+ slug: str
+
+ 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/collection_item_with_id_input.py b/src/webflow/types/collection_item_with_id_input.py
new file mode 100644
index 0000000..0a1aae2
--- /dev/null
+++ b/src/webflow/types/collection_item_with_id_input.py
@@ -0,0 +1,65 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .collection_item_with_id_input_field_data import CollectionItemWithIdInputFieldData
+
+
+class CollectionItemWithIdInput(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()
+ """
+ Unique identifier for the Item
+ """
+
+ cms_locale_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="cmsLocaleId"),
+ pydantic.Field(alias="cmsLocaleId", description="Identifier for the locale of the CMS item"),
+ ] = None
+ last_published: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="lastPublished"),
+ pydantic.Field(alias="lastPublished", description="The date the item was last published"),
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="The date the item was last updated"),
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="The date the item was created"),
+ ] = None
+ is_archived: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="isArchived"),
+ pydantic.Field(alias="isArchived", description="Boolean determining if the Item is set to archived"),
+ ] = None
+ is_draft: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="isDraft"),
+ pydantic.Field(alias="isDraft", description="Boolean determining if the Item is set to draft"),
+ ] = None
+ field_data: typing_extensions.Annotated[
+ typing.Optional[CollectionItemWithIdInputFieldData],
+ FieldMetadata(alias="fieldData"),
+ pydantic.Field(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/types/collection_item_with_id_input_field_data.py b/src/webflow/types/collection_item_with_id_input_field_data.py
new file mode 100644
index 0000000..d27ccab
--- /dev/null
+++ b/src/webflow/types/collection_item_with_id_input_field_data.py
@@ -0,0 +1,27 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class CollectionItemWithIdInputFieldData(UniversalBaseModel):
+ name: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Name of the Item
+ """
+
+ slug: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ URL structure of the Item in your site. Note: Updates to an item slug will break all links referencing the old slug.
+ """
+
+ 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/collection_list.py b/src/webflow/types/collection_list.py
index 683b028..bfa7212 100644
--- a/src/webflow/types/collection_list.py
+++ b/src/webflow/types/collection_list.py
@@ -1,31 +1,23 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from .collection_list_array_item import CollectionListArrayItem
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+class CollectionList(UniversalBaseModel):
+ collections: typing.Optional[typing.List[CollectionListArrayItem]] = pydantic.Field(default=None)
+ """
+ An array of Collections
+ """
-class CollectionList(pydantic.BaseModel):
- collections: typing.Optional[typing.List[CollectionListArrayItem]] = pydantic.Field(
- default=None, description="An array of Collections"
- )
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/collection_list_array_item.py b/src/webflow/types/collection_list_array_item.py
index 2669222..035f7e0 100644
--- a/src/webflow/types/collection_list_array_item.py
+++ b/src/webflow/types/collection_list_array_item.py
@@ -3,46 +3,56 @@
import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class CollectionListArrayItem(pydantic.BaseModel):
+class CollectionListArrayItem(UniversalBaseModel):
"""
A collection object
"""
- id: str = pydantic.Field(description="Unique identifier for a Collection")
- display_name: typing.Optional[str] = pydantic.Field(
- alias="displayName", default=None, description="Name given to the Collection"
- )
- singular_name: typing.Optional[str] = pydantic.Field(
- alias="singularName",
- default=None,
- description="The name of one Item in Collection (e.g. ”Blog Post” if the Collection is called “Blog Posts”)",
- )
- slug: typing.Optional[str] = pydantic.Field(default=None, description="Slug of Collection in Site URL structure")
- created_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="createdOn", default=None, description="The date the collection was created"
- )
- last_updated: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastUpdated", default=None, description="The date the collection was last updated"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ id: str = pydantic.Field()
+ """
+ Unique identifier for a Collection
+ """
+
+ display_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="displayName"),
+ pydantic.Field(alias="displayName", description="Name given to the Collection"),
+ ] = None
+ singular_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="singularName"),
+ pydantic.Field(
+ alias="singularName",
+ description="The name of one Item in Collection (e.g. ”Blog Post” if the Collection is called “Blog Posts”)",
+ ),
+ ] = None
+ slug: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Slug of Collection in Site URL structure
+ """
+
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="The date the collection was created"),
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="The date the collection was last updated"),
+ ] = 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/comment.py b/src/webflow/types/comment.py
new file mode 100644
index 0000000..743c912
--- /dev/null
+++ b/src/webflow/types/comment.py
@@ -0,0 +1,31 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .comment_payload import CommentPayload
+
+
+class Comment(UniversalBaseModel):
+ """
+ The Webhook payload for when a comment thread or reply is made on a Site
+ """
+
+ trigger_type: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="triggerType"),
+ pydantic.Field(alias="triggerType", description="The type of event that triggered the request"),
+ ] = None
+ payload: typing.Optional[CommentPayload] = 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/comment_payload.py b/src/webflow/types/comment_payload.py
new file mode 100644
index 0000000..8b51391
--- /dev/null
+++ b/src/webflow/types/comment_payload.py
@@ -0,0 +1,100 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .comment_payload_author import CommentPayloadAuthor
+from .comment_payload_mentioned_users_item import CommentPayloadMentionedUsersItem
+
+
+class CommentPayload(UniversalBaseModel):
+ """
+ The comment webhook payload contains data for the thread and for replies. Check the type to determine if the payload is for a thread or a reply. The webhook payload may be delayed by up to 5 minutes.
+ """
+
+ thread_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="threadId"),
+ pydantic.Field(alias="threadId", description="Unique identifier for the comment thread"),
+ ] = None
+ comment_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="commentId"),
+ pydantic.Field(alias="commentId", description="Unique identifier for the comment reply"),
+ ] = None
+ type: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The type of comment payload
+ """
+
+ site_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="siteId"),
+ pydantic.Field(alias="siteId", description="The site unique identifier"),
+ ] = None
+ page_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="pageId"),
+ pydantic.Field(alias="pageId", description="The page unique identifier"),
+ ] = None
+ locale_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="localeId"),
+ pydantic.Field(alias="localeId", description="The locale unique identifier"),
+ ] = None
+ item_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="itemId"),
+ pydantic.Field(alias="itemId", description="The item unique identifier"),
+ ] = None
+ breakpoint: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The breakpoint the comment was left on
+ """
+
+ 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(alias="isResolved", description="Boolean determining if the comment thread is resolved"),
+ ]
+ author: CommentPayloadAuthor
+ mentioned_users: typing_extensions.Annotated[
+ typing.List[CommentPayloadMentionedUsersItem],
+ FieldMetadata(alias="mentionedUsers"),
+ pydantic.Field(
+ alias="mentionedUsers",
+ description="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(alias="createdOn", description="The date the item was created"),
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="The date the item was last updated"),
+ ] = 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/comment_payload_author.py b/src/webflow/types/comment_payload_author.py
new file mode 100644
index 0000000..a1f8e03
--- /dev/null
+++ b/src/webflow/types/comment_payload_author.py
@@ -0,0 +1,34 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class CommentPayloadAuthor(UniversalBaseModel):
+ user_id: typing_extensions.Annotated[
+ str,
+ FieldMetadata(alias="userId"),
+ pydantic.Field(alias="userId", description="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_payload_mentioned_users_item.py b/src/webflow/types/comment_payload_mentioned_users_item.py
new file mode 100644
index 0000000..d9e46b1
--- /dev/null
+++ b/src/webflow/types/comment_payload_mentioned_users_item.py
@@ -0,0 +1,34 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class CommentPayloadMentionedUsersItem(UniversalBaseModel):
+ user_id: typing_extensions.Annotated[
+ str,
+ FieldMetadata(alias="userId"),
+ pydantic.Field(alias="userId", description="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_reply.py b/src/webflow/types/comment_reply.py
new file mode 100644
index 0000000..e3d258a
--- /dev/null
+++ b/src/webflow/types/comment_reply.py
@@ -0,0 +1,81 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .comment_reply_author import CommentReplyAuthor
+from .comment_reply_mentioned_users_item import CommentReplyMentionedUsersItem
+
+
+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: str = pydantic.Field()
+ """
+ Unique identifier for the comment thread
+ """
+
+ comment_id: typing_extensions.Annotated[
+ str,
+ FieldMetadata(alias="commentId"),
+ pydantic.Field(alias="commentId", description="The comment reply unique identifier"),
+ ]
+ site_id: typing_extensions.Annotated[
+ str, FieldMetadata(alias="siteId"), pydantic.Field(alias="siteId", description="The site unique identifier")
+ ]
+ page_id: typing_extensions.Annotated[
+ str, FieldMetadata(alias="pageId"), pydantic.Field(alias="pageId", description="The page unique identifier")
+ ]
+ locale_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="localeId"),
+ pydantic.Field(alias="localeId", description="The locale unique identifier"),
+ ] = None
+ breakpoint: str = pydantic.Field()
+ """
+ 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(alias="isResolved", description="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(
+ alias="mentionedUsers",
+ description="List of mentioned users is an empty array until email notifications are sent.",
+ ),
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="The date the item was last updated"),
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="The date the item was created"),
+ ] = 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/comment_reply_author.py b/src/webflow/types/comment_reply_author.py
new file mode 100644
index 0000000..71fece2
--- /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.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+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..5a4cc7c
--- /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.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .comment_reply import CommentReply
+from .comment_reply_list_pagination import CommentReplyListPagination
+
+
+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..580ee06
--- /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.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class CommentReplyListPagination(UniversalBaseModel):
+ limit: int = pydantic.Field()
+ """
+ The limit specified in the request (default 100)
+ """
+
+ offset: int = pydantic.Field()
+ """
+ The offset specified for pagination
+ """
+
+ total: int = 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..7315c20
--- /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.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+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..44f1369
--- /dev/null
+++ b/src/webflow/types/comment_thread.py
@@ -0,0 +1,86 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .comment_thread_author import CommentThreadAuthor
+from .comment_thread_mentioned_users_item import CommentThreadMentionedUsersItem
+
+
+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: str = pydantic.Field()
+ """
+ Unique identifier for the comment thread
+ """
+
+ site_id: typing_extensions.Annotated[
+ str, FieldMetadata(alias="siteId"), pydantic.Field(alias="siteId", description="The site unique identifier")
+ ]
+ page_id: typing_extensions.Annotated[
+ str, FieldMetadata(alias="pageId"), pydantic.Field(alias="pageId", description="The page unique identifier")
+ ]
+ locale_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="localeId"),
+ pydantic.Field(alias="localeId", description="The locale unique identifier"),
+ ] = None
+ item_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="itemId"),
+ pydantic.Field(alias="itemId", description="The item unique identifier"),
+ ] = None
+ breakpoint: str = pydantic.Field()
+ """
+ The breakpoint the comment was left on
+ """
+
+ url: str = pydantic.Field()
+ """
+ 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(alias="isResolved", description="Boolean determining if the comment thread is resolved"),
+ ]
+ author: CommentThreadAuthor
+ mentioned_users: typing_extensions.Annotated[
+ typing.List[CommentThreadMentionedUsersItem],
+ FieldMetadata(alias="mentionedUsers"),
+ pydantic.Field(
+ alias="mentionedUsers",
+ description="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[
+ str,
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="The date the item was created"),
+ ]
+ last_updated: typing_extensions.Annotated[
+ str,
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="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..00cee01
--- /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.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class CommentThreadAuthor(UniversalBaseModel):
+ user_id: typing_extensions.Annotated[
+ str,
+ FieldMetadata(alias="userId"),
+ pydantic.Field(alias="userId", description="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..1b3db57
--- /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.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .comment_thread import CommentThread
+from .comment_thread_list_pagination import CommentThreadListPagination
+
+
+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..e1e22fe
--- /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.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class CommentThreadListPagination(UniversalBaseModel):
+ limit: int = pydantic.Field()
+ """
+ The limit specified in the request (default 100)
+ """
+
+ offset: int = pydantic.Field()
+ """
+ The offset specified for pagination
+ """
+
+ total: int = 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..124037a
--- /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.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class CommentThreadMentionedUsersItem(UniversalBaseModel):
+ user_id: typing_extensions.Annotated[
+ str,
+ FieldMetadata(alias="userId"),
+ pydantic.Field(alias="userId", description="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
new file mode 100644
index 0000000..51f3d72
--- /dev/null
+++ b/src/webflow/types/component.py
@@ -0,0 +1,46 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class Component(UniversalBaseModel):
+ """
+ The Component object
+ """
+
+ id: str = pydantic.Field()
+ """
+ Unique identifier for the Component
+ """
+
+ name: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Component Name
+ """
+
+ group: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The group that the component belongs to
+ """
+
+ description: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Component Description
+ """
+
+ readonly: typing.Optional[bool] = pydantic.Field(default=None)
+ """
+ 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.
+ """
+
+ 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_dom.py b/src/webflow/types/component_dom.py
new file mode 100644
index 0000000..5c2d621
--- /dev/null
+++ b/src/webflow/types/component_dom.py
@@ -0,0 +1,33 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .node import Node
+from .pagination import Pagination
+
+
+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, select or text inputs, submit buttons, or nested component instances.
+ """
+
+ component_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="componentId"),
+ pydantic.Field(alias="componentId", description="Component ID"),
+ ] = None
+ nodes: typing.Optional[typing.List[Node]] = 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/component_instance_node_property_overrides_write.py b/src/webflow/types/component_instance_node_property_overrides_write.py
new file mode 100644
index 0000000..ddcf2cb
--- /dev/null
+++ b/src/webflow/types/component_instance_node_property_overrides_write.py
@@ -0,0 +1,38 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .component_instance_node_property_overrides_write_property_overrides_item import (
+ ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem,
+)
+
+
+class ComponentInstanceNodePropertyOverridesWrite(UniversalBaseModel):
+ """
+ Update text property overrides of a component instance
+ """
+
+ node_id: typing_extensions.Annotated[
+ str, FieldMetadata(alias="nodeId"), pydantic.Field(alias="nodeId", description="Node UUID")
+ ]
+ property_overrides: typing_extensions.Annotated[
+ typing.List[ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem],
+ FieldMetadata(alias="propertyOverrides"),
+ pydantic.Field(
+ alias="propertyOverrides",
+ description="A list of component instance properties to override within the specified secondary locale.",
+ ),
+ ]
+
+ 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_instance_node_property_overrides_write_property_overrides_item.py b/src/webflow/types/component_instance_node_property_overrides_write_property_overrides_item.py
new file mode 100644
index 0000000..13e1256
--- /dev/null
+++ b/src/webflow/types/component_instance_node_property_overrides_write_property_overrides_item.py
@@ -0,0 +1,32 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class ComponentInstanceNodePropertyOverridesWritePropertyOverridesItem(UniversalBaseModel):
+ property_id: typing_extensions.Annotated[
+ str,
+ FieldMetadata(alias="propertyId"),
+ pydantic.Field(alias="propertyId", description="The ID of the property."),
+ ]
+ text: str = pydantic.Field()
+ """
+ The new string or HTML value used to override the component instance property value.
+ The provided value must be compatible with the type of the component instance property.
+ For example, attempting to override a single-line plain-text property with a multi-line
+ value will result in an error.
+ """
+
+ 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_list.py b/src/webflow/types/component_list.py
new file mode 100644
index 0000000..de17894
--- /dev/null
+++ b/src/webflow/types/component_list.py
@@ -0,0 +1,26 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .component import Component
+from .pagination import Pagination
+
+
+class ComponentList(UniversalBaseModel):
+ """
+ List of Components on a site.
+ """
+
+ components: typing.Optional[typing.List[Component]] = 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/component_node.py b/src/webflow/types/component_node.py
new file mode 100644
index 0000000..d091d2a
--- /dev/null
+++ b/src/webflow/types/component_node.py
@@ -0,0 +1,43 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .component_property import ComponentProperty
+
+
+class ComponentNode(UniversalBaseModel):
+ """
+ Represents a component instance within the DOM. It contains details about the component instance, such as its type and properties.
+ """
+
+ id: str = pydantic.Field()
+ """
+ The unique identifier of the component instance node
+ """
+
+ component_id: typing_extensions.Annotated[
+ str,
+ FieldMetadata(alias="componentId"),
+ pydantic.Field(alias="componentId", description="The unique identifier of the component"),
+ ]
+ property_overrides: typing_extensions.Annotated[
+ typing.List[ComponentProperty],
+ FieldMetadata(alias="propertyOverrides"),
+ pydantic.Field(
+ alias="propertyOverrides",
+ description="List of component properties with overrides for a component instance.",
+ ),
+ ]
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/component_properties.py b/src/webflow/types/component_properties.py
new file mode 100644
index 0000000..aa97a9c
--- /dev/null
+++ b/src/webflow/types/component_properties.py
@@ -0,0 +1,33 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .component_property import ComponentProperty
+from .pagination import Pagination
+
+
+class ComponentProperties(UniversalBaseModel):
+ """
+ The Component Properties schema represents a list of properties that store text content. Each property has a unique identifier and can be of different types like plain text or rich text. The schema also provides pagination details for scenarios where there more properties than the limit.
+ """
+
+ component_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="componentId"),
+ pydantic.Field(alias="componentId", description="Component ID"),
+ ] = None
+ properties: typing.Optional[typing.List[ComponentProperty]] = 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/component_property.py b/src/webflow/types/component_property.py
new file mode 100644
index 0000000..4583f4d
--- /dev/null
+++ b/src/webflow/types/component_property.py
@@ -0,0 +1,45 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .component_property_type import ComponentPropertyType
+from .text import Text
+
+
+class ComponentProperty(UniversalBaseModel):
+ """
+ Represents a property of a component instance in the DOM. A property contains a list of both the raw text and the HTML representation, allowing for flexibility in rendering and processing. Additional attributes can be associated with the text for styling or other purposes.
+ """
+
+ property_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="propertyId"),
+ pydantic.Field(alias="propertyId", description="The ID of the property."),
+ ] = None
+ type: typing.Optional[ComponentPropertyType] = pydantic.Field(default=None)
+ """
+ The type of the property.
+ """
+
+ label: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The label of the property in the UI.
+ """
+
+ text: typing.Optional[Text] = pydantic.Field(default=None)
+ """
+ Represents text content within the DOM. It contains both the raw text and its HTML representation.
+ """
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/component_property_type.py b/src/webflow/types/component_property_type.py
new file mode 100644
index 0000000..117b2fe
--- /dev/null
+++ b/src/webflow/types/component_property_type.py
@@ -0,0 +1,5 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+ComponentPropertyType = typing.Union[typing.Literal["Plain Text", "Rich Text", "Alt Text"], typing.Any]
diff --git a/src/webflow/types/error_details_item.py b/src/webflow/types/conflict.py
similarity index 54%
rename from src/webflow/types/error_details_item.py
rename to src/webflow/types/conflict.py
index 693e235..f90bc65 100644
--- a/src/webflow/types/error_details_item.py
+++ b/src/webflow/types/conflict.py
@@ -2,4 +2,4 @@
import typing
-ErrorDetailsItem = typing.Union[str, typing.Dict[str, typing.Any]]
+Conflict = typing.Any
diff --git a/src/webflow/types/custom_code_block.py b/src/webflow/types/custom_code_block.py
index 20cc019..ea8c8fb 100644
--- a/src/webflow/types/custom_code_block.py
+++ b/src/webflow/types/custom_code_block.py
@@ -3,48 +3,51 @@
import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .custom_code_block_type import CustomCodeBlockType
from .scripts import Scripts
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class CustomCodeBlock(pydantic.BaseModel):
+class CustomCodeBlock(UniversalBaseModel):
"""
A specific instance of Custom Code applied to a Site or Page
"""
- site_id: typing.Optional[str] = pydantic.Field(
- alias="siteId", default=None, description="The Site id where the custom code was applied"
- )
- page_id: typing.Optional[str] = pydantic.Field(
- alias="pageId", default=None, description="The Page id (if applied at Page-level)"
- )
- type: typing.Optional[CustomCodeBlockType] = pydantic.Field(
- default=None, description="Whether the Custom Code script is applied at the Site-level or Page-level"
- )
+ site_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="siteId"),
+ pydantic.Field(alias="siteId", description="The Site ID where the custom code was applied"),
+ ] = None
+ page_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="pageId"),
+ pydantic.Field(alias="pageId", description="The Page ID (if applied at Page-level)"),
+ ] = None
+ type: typing.Optional[CustomCodeBlockType] = pydantic.Field(default=None)
+ """
+ Whether the Custom Code script is applied at the Site-level or Page-level
+ """
+
scripts: typing.Optional[Scripts] = None
- created_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="createdOn", default=None, description="The date the Block was created"
- )
- last_updated: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastUpdated", default=None, description="The date the Block was most recently updated"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="The date the Block was created"),
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="The date the Block was most recently updated"),
+ ] = 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_code_block_type.py b/src/webflow/types/custom_code_block_type.py
index 2d1673d..4b8cf2e 100644
--- a/src/webflow/types/custom_code_block_type.py
+++ b/src/webflow/types/custom_code_block_type.py
@@ -1,21 +1,5 @@
# This file was auto-generated by Fern from our API Definition.
-import enum
import typing
-T_Result = typing.TypeVar("T_Result")
-
-
-class CustomCodeBlockType(str, enum.Enum):
- """
- Whether the Custom Code script is applied at the Site-level or Page-level
- """
-
- PAGE = "page"
- SITE = "site"
-
- def visit(self, page: typing.Callable[[], T_Result], site: typing.Callable[[], T_Result]) -> T_Result:
- if self is CustomCodeBlockType.PAGE:
- return page()
- if self is CustomCodeBlockType.SITE:
- return site()
+CustomCodeBlockType = typing.Union[typing.Literal["page", "site"], typing.Any]
diff --git a/src/webflow/types/custom_code_hosted_response.py b/src/webflow/types/custom_code_hosted_response.py
new file mode 100644
index 0000000..ddc3bab
--- /dev/null
+++ b/src/webflow/types/custom_code_hosted_response.py
@@ -0,0 +1,71 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class CustomCodeHostedResponse(UniversalBaseModel):
+ """
+ Registered custom code for application
+ """
+
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Human readable id, derived from the user-specified display name
+ """
+
+ can_copy: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="canCopy"),
+ pydantic.Field(
+ alias="canCopy", description="Define whether the script can be copied on site duplication and transfer"
+ ),
+ ] = None
+ display_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="displayName"),
+ pydantic.Field(
+ alias="displayName",
+ description="User-facing name for the script. Must be between 1 and 50 alphanumeric characters",
+ ),
+ ] = None
+ hosted_location: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="hostedLocation"),
+ pydantic.Field(alias="hostedLocation", description="URI for an externally hosted script location"),
+ ] = None
+ integrity_hash: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="integrityHash"),
+ pydantic.Field(
+ alias="integrityHash",
+ description="Sub-Resource Integrity Hash. Only required for externally hosted scripts (passed via hostedLocation)",
+ ),
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="Timestamp when the script version was created"),
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="Timestamp when the script version was last updated"),
+ ] = None
+ version: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ A Semantic Version (SemVer) string, denoting the version of the script
+ """
+
+ 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_code_inline_response.py b/src/webflow/types/custom_code_inline_response.py
new file mode 100644
index 0000000..971d0d1
--- /dev/null
+++ b/src/webflow/types/custom_code_inline_response.py
@@ -0,0 +1,71 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class CustomCodeInlineResponse(UniversalBaseModel):
+ """
+ Registered custom code for application
+ """
+
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Human readable id, derived from the user-specified display name
+ """
+
+ can_copy: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="canCopy"),
+ pydantic.Field(
+ alias="canCopy", description="Define whether the script can be copied on site duplication and transfer"
+ ),
+ ] = None
+ display_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="displayName"),
+ pydantic.Field(
+ alias="displayName",
+ description="User-facing name for the script. Must be between 1 and 50 alphanumeric characters",
+ ),
+ ] = None
+ hosted_location: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="hostedLocation"),
+ pydantic.Field(alias="hostedLocation", description="URI for an externally hosted script location"),
+ ] = None
+ integrity_hash: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="integrityHash"),
+ pydantic.Field(
+ alias="integrityHash",
+ description="Sub-Resource Integrity Hash. Only required for externally hosted scripts (passed via hostedLocation)",
+ ),
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="Timestamp when the script version was created"),
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="Timestamp when the script version was last updated"),
+ ] = None
+ version: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ A Semantic Version (SemVer) string, denoting the version of the script
+ """
+
+ 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_code_response.py b/src/webflow/types/custom_code_response.py
deleted file mode 100644
index 2765ca9..0000000
--- a/src/webflow/types/custom_code_response.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import datetime as dt
-import typing
-
-from ..core.datetime_utils import serialize_datetime
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class CustomCodeResponse(pydantic.BaseModel):
- """
- Registered custom code for application
- """
-
- id: typing.Optional[str] = pydantic.Field(
- default=None, description="Human readable id, derived from the user-specified display name"
- )
- created_on: typing.Optional[str] = pydantic.Field(
- alias="createdOn", default=None, description="Timestamp when the script version was created"
- )
- last_updated: typing.Optional[str] = pydantic.Field(
- alias="lastUpdated", default=None, description="Timestamp when the script version was last updated"
- )
- hosted_location: typing.Optional[str] = pydantic.Field(
- alias="hostedLocation", default=None, description="URI for an externally hosted script location"
- )
- integrity_hash: typing.Optional[str] = pydantic.Field(
- alias="integrityHash",
- default=None,
- description="Sub-Resource Integrity Hash. Only required for externally hosted scripts (passed via hostedLocation)",
- )
- can_copy: typing.Optional[bool] = pydantic.Field(
- alias="canCopy",
- default=None,
- description="Define whether the script can be copied on site duplication and transfer",
- )
- version: typing.Optional[str] = pydantic.Field(
- default=None, description="A Semantic Version (SemVer) string, denoting the version of the script"
- )
- display_name: typing.Optional[str] = pydantic.Field(
- alias="displayName", default=None, description="User-facing name for the script"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
diff --git a/src/webflow/types/custom_role.py b/src/webflow/types/custom_role.py
new file mode 100644
index 0000000..5c45925
--- /dev/null
+++ b/src/webflow/types/custom_role.py
@@ -0,0 +1,30 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class CustomRole(UniversalBaseModel):
+ role_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="roleName"),
+ pydantic.Field(alias="roleName", description="The name of the custom role"),
+ ] = None
+ previous_role_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="previousRoleName"),
+ pydantic.Field(alias="previousRoleName", description="The previous name of the custom role"),
+ ] = 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.py b/src/webflow/types/custom_role_audit_log_item.py
new file mode 100644
index 0000000..79938a2
--- /dev/null
+++ b/src/webflow/types/custom_role_audit_log_item.py
@@ -0,0 +1,28 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .custom_role import CustomRole
+from .custom_role_audit_log_item_event_sub_type import CustomRoleAuditLogItemEventSubType
+
+
+class CustomRoleAuditLogItem(UniversalBaseModel):
+ event_sub_type: typing_extensions.Annotated[
+ typing.Optional[CustomRoleAuditLogItemEventSubType],
+ FieldMetadata(alias="eventSubType"),
+ pydantic.Field(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 c6e1d9a..fe23cac 100644
--- a/src/webflow/types/dom.py
+++ b/src/webflow/types/dom.py
@@ -3,35 +3,43 @@
import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .node import Node
from .pagination import Pagination
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class Dom(pydantic.BaseModel):
+class Dom(UniversalBaseModel):
"""
- The DOM (Document Object Model) schema represents the content structure of a web page. It captures various content nodes, such as text and images, along with their associated attributes. Each node has a unique identifier and can be of different types like text or image. The schema also provides pagination details for scenarios where the content nodes are too many to be fetched in a single request.
+ The DOM (Document Object Model) schema represents the content structure of a web page or component. It captures various content nodes along with their associated attributes. Each node has a unique identifier and can be of different types like text, image or component-instance. The schema also provides pagination details for scenarios where the content nodes are too many to be fetched in a single request.
"""
- page_id: typing.Optional[str] = pydantic.Field(alias="pageId", default=None, description="Page ID")
+ page_id: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="pageId"), pydantic.Field(alias="pageId", description="Page ID")
+ ] = None
+ branch_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="branchId"),
+ pydantic.Field(
+ alias="branchId",
+ description="The unique identifier of a [specific page branch.](https://help.webflow.com/hc/en-us/articles/33961355506195-Page-branching)",
+ ),
+ ] = None
nodes: typing.Optional[typing.List[Node]] = None
pagination: typing.Optional[Pagination] = None
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="The date the page dom was most recently updated"),
+ ] = 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/domain.py b/src/webflow/types/domain.py
index 1b69fa5..b82a1fd 100644
--- a/src/webflow/types/domain.py
+++ b/src/webflow/types/domain.py
@@ -3,27 +3,34 @@
import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class Domain(pydantic.BaseModel):
- id: str = pydantic.Field(description="Unique identifier for the Domain")
- url: typing.Optional[str] = pydantic.Field(default=None, description="The registered Domain name")
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- json_encoders = {dt.datetime: serialize_datetime}
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class Domain(UniversalBaseModel):
+ id: str = pydantic.Field()
+ """
+ Unique identifier for the Domain
+ """
+
+ url: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The registered Domain name
+ """
+
+ last_published: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="lastPublished"),
+ pydantic.Field(alias="lastPublished", description="The date the custom domain was last published to"),
+ ] = 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/domains.py b/src/webflow/types/domains.py
index e9bde11..959efa0 100644
--- a/src/webflow/types/domains.py
+++ b/src/webflow/types/domains.py
@@ -1,30 +1,26 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .domain import Domain
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+class Domains(UniversalBaseModel):
+ custom_domains: typing_extensions.Annotated[
+ typing.Optional[typing.List[Domain]],
+ FieldMetadata(alias="customDomains"),
+ pydantic.Field(alias="customDomains"),
+ ] = None
-class Domains(pydantic.BaseModel):
- custom_domains: typing.Optional[typing.List[Domain]] = pydantic.Field(alias="customDomains", default=None)
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/duplicate_user_email.py b/src/webflow/types/duplicate_user_email.py
deleted file mode 100644
index cfc148a..0000000
--- a/src/webflow/types/duplicate_user_email.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import datetime as dt
-import typing
-
-from ..core.datetime_utils import serialize_datetime
-from .error_details_item import ErrorDetailsItem
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class DuplicateUserEmail(pydantic.BaseModel):
- code: typing.Optional[str] = pydantic.Field(default=None, description="Error code")
- message: typing.Optional[str] = pydantic.Field(default=None, description="Error message")
- external_reference: typing.Optional[str] = pydantic.Field(
- alias="externalReference", default=None, description="Link to more information"
- )
- details: typing.Optional[typing.List[ErrorDetailsItem]] = pydantic.Field(
- default=None, description="Array of errors"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
diff --git a/src/webflow/types/ecommerce_settings.py b/src/webflow/types/ecommerce_settings.py
index 6b6b110..b3dd070 100644
--- a/src/webflow/types/ecommerce_settings.py
+++ b/src/webflow/types/ecommerce_settings.py
@@ -3,39 +3,38 @@
import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class EcommerceSettings(pydantic.BaseModel):
+class EcommerceSettings(UniversalBaseModel):
"""
Ecommerce settings for a Webflow Site
"""
- site_id: typing.Optional[str] = pydantic.Field(
- alias="siteId", default=None, description="The identifier of the Site"
- )
- created_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="createdOn", default=None, description="Date that the Site was created on"
- )
- default_currency: typing.Optional[str] = pydantic.Field(
- alias="defaultCurrency", default=None, description="The three-letter ISO currency code for the Site"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ site_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="siteId"),
+ pydantic.Field(alias="siteId", description="The identifier of the Site"),
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="Date that the Site was created on"),
+ ] = None
+ default_currency: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="defaultCurrency"),
+ pydantic.Field(alias="defaultCurrency", description="The three-letter ISO currency code for the Site"),
+ ] = 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/error.py b/src/webflow/types/error.py
index c8574ab..1b069e3 100644
--- a/src/webflow/types/error.py
+++ b/src/webflow/types/error.py
@@ -1,37 +1,40 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
-from .error_details_item import ErrorDetailsItem
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class Error(pydantic.BaseModel):
- code: typing.Optional[str] = pydantic.Field(default=None, description="Error code")
- message: typing.Optional[str] = pydantic.Field(default=None, description="Error message")
- external_reference: typing.Optional[str] = pydantic.Field(
- alias="externalReference", default=None, description="Link to more information"
- )
- details: typing.Optional[typing.List[ErrorDetailsItem]] = pydantic.Field(
- default=None, description="Array of errors"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .error_code import ErrorCode
+
+
+class Error(UniversalBaseModel):
+ code: typing.Optional[ErrorCode] = pydantic.Field(default=None)
+ """
+ Error code
+ """
+
+ message: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Error message
+ """
+
+ external_reference: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="externalReference"),
+ pydantic.Field(alias="externalReference", description="Link to more information"),
+ ] = None
+ details: typing.Optional[typing.List[typing.Any]] = pydantic.Field(default=None)
+ """
+ Array of errors
+ """
+
+ 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/error_code.py b/src/webflow/types/error_code.py
new file mode 100644
index 0000000..f9149eb
--- /dev/null
+++ b/src/webflow/types/error_code.py
@@ -0,0 +1,38 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+ErrorCode = typing.Union[
+ typing.Literal[
+ "bad_request",
+ "collection_not_found",
+ "conflict",
+ "duplicate_collection",
+ "duplicate_user_email",
+ "ecommerce_not_enabled",
+ "forbidden",
+ "forms_require_republish",
+ "incompatible_webhook_filter",
+ "internal_error",
+ "invalid_auth_version",
+ "invalid_credentials",
+ "invalid_domain",
+ "invalid_user_email",
+ "item_not_found",
+ "missing_scopes",
+ "no_domains",
+ "not_authorized",
+ "not_enterprise_plan_site",
+ "not_enterprise_plan_workspace",
+ "order_not_found",
+ "resource_not_found",
+ "too_many_requests",
+ "unsupported_version",
+ "unsupported_webhook_trigger_type",
+ "user_limit_reached",
+ "user_not_found",
+ "users_not_enabled",
+ "validation_error",
+ ],
+ typing.Any,
+]
diff --git a/src/webflow/types/field.py b/src/webflow/types/field.py
index a2f8117..7eb4b77 100644
--- a/src/webflow/types/field.py
+++ b/src/webflow/types/field.py
@@ -1,49 +1,63 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .field_type import FieldType
+from .field_validations import FieldValidations
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class Field(pydantic.BaseModel):
+class Field(UniversalBaseModel):
"""
The details of a field in a collection
"""
- id: str = pydantic.Field(description="Unique identifier for a Field")
- is_required: bool = pydantic.Field(
- alias="isRequired", description="define whether a field is required in a collection"
- )
- is_editable: typing.Optional[bool] = pydantic.Field(
- alias="isEditable", default=None, description="Define whether the field is editable"
- )
- type: FieldType = pydantic.Field(description="Choose these appropriate field type for your collection data")
- slug: typing.Optional[str] = pydantic.Field(
- default=None,
- description='Slug of Field in Site URL structure. Slugs should be all lowercase with no spaces. Any spaces will be converted to "-."',
- )
- display_name: str = pydantic.Field(alias="displayName", description="The name of a field")
- help_text: typing.Optional[str] = pydantic.Field(
- alias="helpText", default=None, description="Additional text to help anyone filling out this field"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ id: str = pydantic.Field()
+ """
+ Unique identifier for a Field
+ """
+
+ is_required: typing_extensions.Annotated[
+ bool,
+ FieldMetadata(alias="isRequired"),
+ pydantic.Field(alias="isRequired", description="define whether a field is required in a collection"),
+ ]
+ is_editable: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="isEditable"),
+ pydantic.Field(alias="isEditable", description="Define whether the field is editable"),
+ ] = None
+ type: FieldType = pydantic.Field()
+ """
+ Choose these appropriate field type for your collection data
+ """
+
+ slug: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Slug of Field in Site URL structure. Slugs should be all lowercase with no spaces. Any spaces will be converted to "-."
+ """
+
+ display_name: typing_extensions.Annotated[
+ str, FieldMetadata(alias="displayName"), pydantic.Field(alias="displayName", description="The name of a field")
+ ]
+ help_text: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="helpText"),
+ pydantic.Field(alias="helpText", description="Additional text to help anyone filling out this field"),
+ ] = None
+ 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:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/field_create.py b/src/webflow/types/field_create.py
new file mode 100644
index 0000000..0d312e5
--- /dev/null
+++ b/src/webflow/types/field_create.py
@@ -0,0 +1,9 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from .option_field import OptionField
+from .reference_field import ReferenceField
+from .static_field import StaticField
+
+FieldCreate = typing.Union[StaticField, OptionField, ReferenceField]
diff --git a/src/webflow/types/field_type.py b/src/webflow/types/field_type.py
index d40aa66..e3495ce 100644
--- a/src/webflow/types/field_type.py
+++ b/src/webflow/types/field_type.py
@@ -1,69 +1,26 @@
# This file was auto-generated by Fern from our API Definition.
-import enum
import typing
-T_Result = typing.TypeVar("T_Result")
-
-
-class FieldType(str, enum.Enum):
- """
- Choose these appropriate field type for your collection data
- """
-
- PLAIN_TEXT = "PlainText"
- RICH_TEXT = "RichText"
- IMAGE = "Image"
- MULTI_IMAGE = "MultiImage"
- VIDEO = "Video"
- LINK = "Link"
- EMAIL = "Email"
- PHONE = "Phone"
- NUMBER = "Number"
- DATE_TIME = "DateTime"
- BOOLEAN = "Boolean"
- COLOR = "Color"
- EXT_FILE_REF = "ExtFileRef"
-
- def visit(
- self,
- plain_text: typing.Callable[[], T_Result],
- rich_text: typing.Callable[[], T_Result],
- image: typing.Callable[[], T_Result],
- multi_image: typing.Callable[[], T_Result],
- video: typing.Callable[[], T_Result],
- link: typing.Callable[[], T_Result],
- email: typing.Callable[[], T_Result],
- phone: typing.Callable[[], T_Result],
- number: typing.Callable[[], T_Result],
- date_time: typing.Callable[[], T_Result],
- boolean: typing.Callable[[], T_Result],
- color: typing.Callable[[], T_Result],
- ext_file_ref: typing.Callable[[], T_Result],
- ) -> T_Result:
- if self is FieldType.PLAIN_TEXT:
- return plain_text()
- if self is FieldType.RICH_TEXT:
- return rich_text()
- if self is FieldType.IMAGE:
- return image()
- if self is FieldType.MULTI_IMAGE:
- return multi_image()
- if self is FieldType.VIDEO:
- return video()
- if self is FieldType.LINK:
- return link()
- if self is FieldType.EMAIL:
- return email()
- if self is FieldType.PHONE:
- return phone()
- if self is FieldType.NUMBER:
- return number()
- if self is FieldType.DATE_TIME:
- return date_time()
- if self is FieldType.BOOLEAN:
- return boolean()
- if self is FieldType.COLOR:
- return color()
- if self is FieldType.EXT_FILE_REF:
- return ext_file_ref()
+FieldType = typing.Union[
+ typing.Literal[
+ "Color",
+ "DateTime",
+ "Email",
+ "ExtFileRef",
+ "File",
+ "Image",
+ "Link",
+ "MultiImage",
+ "MultiReference",
+ "Number",
+ "Option",
+ "Phone",
+ "PlainText",
+ "Reference",
+ "RichText",
+ "Switch",
+ "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..40f076b
--- /dev/null
+++ b/src/webflow/types/field_validations.py
@@ -0,0 +1,30 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .field_validations_additional_properties import FieldValidationsAdditionalProperties
+
+
+class FieldValidations(UniversalBaseModel):
+ """
+ The validations for the field
+ """
+
+ additional_properties: typing_extensions.Annotated[
+ typing.Optional[FieldValidationsAdditionalProperties],
+ FieldMetadata(alias="additionalProperties"),
+ pydantic.Field(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..845d42f
--- /dev/null
+++ b/src/webflow/types/field_validations_additional_properties.py
@@ -0,0 +1,11 @@
+# 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..0c676dd
--- /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.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class FieldValidationsAdditionalPropertiesAdditionalProperties(UniversalBaseModel):
+ additional_properties: typing_extensions.Annotated[
+ typing.Any, FieldMetadata(alias="additionalProperties"), pydantic.Field(alias="additionalProperties")
+ ]
+
+ 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/forbidden_error_body.py b/src/webflow/types/forbidden_error_body.py
new file mode 100644
index 0000000..24bdcf5
--- /dev/null
+++ b/src/webflow/types/forbidden_error_body.py
@@ -0,0 +1,8 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from .invalid_scopes import InvalidScopes
+from .not_enterprise_plan_site import NotEnterprisePlanSite
+
+ForbiddenErrorBody = typing.Union[InvalidScopes, NotEnterprisePlanSite]
diff --git a/src/webflow/types/form.py b/src/webflow/types/form.py
index 82a2f69..14c7fd9 100644
--- a/src/webflow/types/form.py
+++ b/src/webflow/types/form.py
@@ -3,55 +3,85 @@
import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .form_field import FormField
from .form_response_settings import FormResponseSettings
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class Form(pydantic.BaseModel):
- id: typing.Optional[str] = pydantic.Field(default=None, description="The unique id for the Form")
- display_name: typing.Optional[str] = pydantic.Field(
- alias="displayName", default=None, description="The Form name displayed on the site"
- )
- site_id: typing.Optional[str] = pydantic.Field(
- alias="siteId", default=None, description="The unique id of the Site the Form belongs to"
- )
- site_domain_id: typing.Optional[str] = pydantic.Field(
- alias="siteDomainId", default=None, description="The unique id corresponding to the site's Domain name"
- )
- page_id: typing.Optional[str] = pydantic.Field(
- alias="pageId", default=None, description="The unique id for the Page on which the Form is placed"
- )
- page_name: typing.Optional[str] = pydantic.Field(
- alias="pageName", default=None, description="The user-visible name of the Page where the Form is placed"
- )
- workspace_id: typing.Optional[str] = pydantic.Field(
- alias="workspaceId", default=None, description="The unique id of the Workspace the Site belongs to"
- )
- created_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="createdOn", default=None, description="Date that the Form was created on"
- )
- last_updated: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastUpdated", default=None, description="Date that the Form was last updated on"
- )
- fields: typing.Optional[typing.List[FormField]] = None
- response_settings: typing.Optional[FormResponseSettings] = pydantic.Field(alias="responseSettings", default=None)
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+
+class Form(UniversalBaseModel):
+ """
+ A Webflow form
+ """
+
+ display_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="displayName"),
+ pydantic.Field(alias="displayName", description="The Form name displayed on the site"),
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="Date that the Form was created on"),
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="Date that the Form was last updated on"),
+ ] = None
+ fields: typing.Optional[FormField] = pydantic.Field(default=None)
+ """
+ A collection of form field objects
+ """
+
+ response_settings: typing_extensions.Annotated[
+ typing.Optional[FormResponseSettings],
+ FieldMetadata(alias="responseSettings"),
+ pydantic.Field(alias="responseSettings", description="Settings for form responses"),
+ ] = None
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The unique ID for the Form
+ """
+
+ site_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="siteId"),
+ pydantic.Field(alias="siteId", description="The unique ID of the Site the Form belongs to"),
+ ] = None
+ site_domain_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="siteDomainId"),
+ pydantic.Field(alias="siteDomainId", description="The unique ID corresponding to the site's Domain name"),
+ ] = None
+ page_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="pageId"),
+ pydantic.Field(alias="pageId", description="The unique ID for the Page on which the Form is placed"),
+ ] = None
+ page_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="pageName"),
+ pydantic.Field(alias="pageName", description="The user-visible name of the Page where the Form is placed"),
+ ] = None
+ form_element_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="formElementId"),
+ pydantic.Field(alias="formElementId", description="The unique ID of the Form element"),
+ ] = None
+ workspace_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="workspaceId"),
+ pydantic.Field(alias="workspaceId", description="The unique ID of the Workspace the Site belongs to"),
+ ] = 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/form_field_value.py b/src/webflow/types/form_field_value.py
index dafb390..51e8102 100644
--- a/src/webflow/types/form_field_value.py
+++ b/src/webflow/types/form_field_value.py
@@ -1,37 +1,45 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .form_field_value_type import FormFieldValueType
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class FormFieldValue(pydantic.BaseModel):
- display_name: typing.Optional[str] = pydantic.Field(
- alias="displayName", default=None, description="The field name displayed on the site"
- )
- type: typing.Optional[FormFieldValueType] = pydantic.Field(default=None, description="The field type")
- placeholder: typing.Optional[str] = pydantic.Field(default=None, description="The placeholder text for the field")
- user_visible: typing.Optional[bool] = pydantic.Field(
- alias="userVisible", default=None, description="Whether the field is visible to the user"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+
+class FormFieldValue(UniversalBaseModel):
+ """
+ An object containing field info for a specific fieldID.
+ """
+
+ display_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="displayName"),
+ pydantic.Field(alias="displayName", description="The field name displayed on the site"),
+ ] = None
+ type: typing.Optional[FormFieldValueType] = pydantic.Field(default=None)
+ """
+ The field type
+ """
+
+ placeholder: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The placeholder text for the field
+ """
+
+ user_visible: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="userVisible"),
+ pydantic.Field(alias="userVisible", description="Whether the field is visible to the user"),
+ ] = 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/form_field_value_type.py b/src/webflow/types/form_field_value_type.py
index 97b8cae..d4d76d0 100644
--- a/src/webflow/types/form_field_value_type.py
+++ b/src/webflow/types/form_field_value_type.py
@@ -1,37 +1,5 @@
# This file was auto-generated by Fern from our API Definition.
-import enum
import typing
-T_Result = typing.TypeVar("T_Result")
-
-
-class FormFieldValueType(str, enum.Enum):
- """
- The field type
- """
-
- PLAIN = "Plain"
- EMAIL = "Email"
- PASSWORD = "Password"
- PHONE = "Phone"
- NUMBER = "Number"
-
- def visit(
- self,
- plain: typing.Callable[[], T_Result],
- email: typing.Callable[[], T_Result],
- password: typing.Callable[[], T_Result],
- phone: typing.Callable[[], T_Result],
- number: typing.Callable[[], T_Result],
- ) -> T_Result:
- if self is FormFieldValueType.PLAIN:
- return plain()
- if self is FormFieldValueType.EMAIL:
- return email()
- if self is FormFieldValueType.PASSWORD:
- return password()
- if self is FormFieldValueType.PHONE:
- return phone()
- if self is FormFieldValueType.NUMBER:
- return number()
+FormFieldValueType = typing.Union[typing.Literal["Plain", "Email", "Password", "Phone", "Number"], typing.Any]
diff --git a/src/webflow/types/form_list.py b/src/webflow/types/form_list.py
index c3f50c5..c8fe917 100644
--- a/src/webflow/types/form_list.py
+++ b/src/webflow/types/form_list.py
@@ -1,31 +1,22 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from .form import Form
from .pagination import Pagination
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class FormList(pydantic.BaseModel):
+class FormList(UniversalBaseModel):
forms: typing.Optional[typing.List[Form]] = None
pagination: typing.Optional[Pagination] = None
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/form_response_settings.py b/src/webflow/types/form_response_settings.py
index 06c1264..0acae41 100644
--- a/src/webflow/types/form_response_settings.py
+++ b/src/webflow/types/form_response_settings.py
@@ -1,42 +1,48 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class FormResponseSettings(pydantic.BaseModel):
- send_email_confirmation: typing.Optional[bool] = pydantic.Field(
- alias="sendEmailConfirmation", default=None, description="Whether to send an email confirmation to the user"
- )
- redirect_url: typing.Optional[str] = pydantic.Field(
- alias="redirectUrl", default=None, description="The url or path to redirect the user to after form submission"
- )
- redirect_method: typing.Optional[str] = pydantic.Field(
- alias="redirectMethod",
- default=None,
- description="The HTTP request method to use for the redirectUrl (eg. POST or GET)",
- )
- redirect_action: typing.Optional[str] = pydantic.Field(
- alias="redirectAction", default=None, description="The action to take after form submission"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class FormResponseSettings(UniversalBaseModel):
+ """
+ Settings for form responses
+ """
+
+ redirect_url: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="redirectUrl"),
+ pydantic.Field(
+ alias="redirectUrl", description="The url or path to redirect the user to after form submission"
+ ),
+ ] = None
+ redirect_method: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="redirectMethod"),
+ pydantic.Field(
+ alias="redirectMethod", description="The HTTP request method to use for the redirectUrl (eg. POST or GET)"
+ ),
+ ] = None
+ redirect_action: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="redirectAction"),
+ pydantic.Field(alias="redirectAction", description="The action to take after form submission"),
+ ] = None
+ send_email_confirmation: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="sendEmailConfirmation"),
+ pydantic.Field(alias="sendEmailConfirmation", description="Whether to send an email confirmation to the user"),
+ ] = 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/form_submission.py b/src/webflow/types/form_submission.py
index c32d501..adf12b7 100644
--- a/src/webflow/types/form_submission.py
+++ b/src/webflow/types/form_submission.py
@@ -3,42 +3,49 @@
import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class FormSubmission(pydantic.BaseModel):
- id: typing.Optional[str] = pydantic.Field(default=None, description="The unique id of the Form submission")
- display_name: typing.Optional[str] = pydantic.Field(
- alias="displayName", default=None, description="The Form name displayed on the site"
- )
- site_id: typing.Optional[str] = pydantic.Field(
- alias="siteId", default=None, description="The unique id of the Site the Form belongs to"
- )
- workspace_id: typing.Optional[str] = pydantic.Field(
- alias="workspaceId", default=None, description="The unique id of the Workspace the Site belongs to"
- )
- date_submitted: typing.Optional[dt.datetime] = pydantic.Field(
- alias="dateSubmitted", default=None, description="Date that the Form was submitted on"
- )
- form_response: typing.Optional[typing.Dict[str, typing.Any]] = pydantic.Field(
- alias="formResponse", default=None, description="The data submitted in the Form"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class FormSubmission(UniversalBaseModel):
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The unique ID of the Form submission
+ """
+
+ display_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="displayName"),
+ pydantic.Field(alias="displayName", description="The Form name displayed on the site"),
+ ] = None
+ site_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="siteId"),
+ pydantic.Field(alias="siteId", description="The unique ID of the Site the Form belongs to"),
+ ] = None
+ workspace_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="workspaceId"),
+ pydantic.Field(alias="workspaceId", description="The unique ID of the Workspace the Site belongs to"),
+ ] = None
+ date_submitted: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="dateSubmitted"),
+ pydantic.Field(alias="dateSubmitted", description="Date that the Form was submitted on"),
+ ] = None
+ form_response: typing_extensions.Annotated[
+ typing.Optional[typing.Dict[str, typing.Any]],
+ FieldMetadata(alias="formResponse"),
+ pydantic.Field(alias="formResponse", description="The data submitted in the Form"),
+ ] = 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/form_submission_list.py b/src/webflow/types/form_submission_list.py
index 78beebd..356c370 100644
--- a/src/webflow/types/form_submission_list.py
+++ b/src/webflow/types/form_submission_list.py
@@ -1,31 +1,28 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .form_submission import FormSubmission
from .pagination import Pagination
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class FormSubmissionList(pydantic.BaseModel):
- submissions: typing.Optional[typing.List[FormSubmission]] = None
+class FormSubmissionList(UniversalBaseModel):
+ form_submissions: typing_extensions.Annotated[
+ typing.Optional[typing.List[FormSubmission]],
+ FieldMetadata(alias="formSubmissions"),
+ pydantic.Field(alias="formSubmissions"),
+ ] = None
pagination: typing.Optional[Pagination] = None
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/form_submission_trigger.py b/src/webflow/types/form_submission_trigger.py
new file mode 100644
index 0000000..f7c31f7
--- /dev/null
+++ b/src/webflow/types/form_submission_trigger.py
@@ -0,0 +1,34 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .form_submission_trigger_payload import FormSubmissionTriggerPayload
+
+
+class FormSubmissionTrigger(UniversalBaseModel):
+ """
+ The Webhook payload for when a form is submitted
+ """
+
+ trigger_type: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="triggerType"),
+ pydantic.Field(alias="triggerType", description="The type of event that triggered the request"),
+ ] = None
+ payload: typing.Optional[FormSubmissionTriggerPayload] = pydantic.Field(default=None)
+ """
+ The payload of data sent from Webflow
+ """
+
+ 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/form_submission_trigger_payload.py b/src/webflow/types/form_submission_trigger_payload.py
new file mode 100644
index 0000000..d715049
--- /dev/null
+++ b/src/webflow/types/form_submission_trigger_payload.py
@@ -0,0 +1,65 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .form_submission_trigger_payload_schema_item import FormSubmissionTriggerPayloadSchemaItem
+
+
+class FormSubmissionTriggerPayload(UniversalBaseModel):
+ """
+ The payload of data sent from Webflow
+ """
+
+ name: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The name of the form
+ """
+
+ site_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="siteId"),
+ pydantic.Field(alias="siteId", description="The ID of the site that the form was submitted from"),
+ ] = None
+ data: typing.Optional[typing.Dict[str, typing.Any]] = pydantic.Field(default=None)
+ """
+ The data submitted in the form
+ """
+
+ schema_: typing_extensions.Annotated[
+ typing.Optional[typing.List[FormSubmissionTriggerPayloadSchemaItem]],
+ FieldMetadata(alias="schema"),
+ pydantic.Field(alias="schema", description="A list of fields from the submitted form"),
+ ] = None
+ submitted_at: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="submittedAt"),
+ pydantic.Field(alias="submittedAt", description="The timestamp the form was submitted"),
+ ] = None
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ the ID of the event
+ """
+
+ form_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="formId"),
+ pydantic.Field(alias="formId", description="The ID of the form submission"),
+ ] = None
+ form_element_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="formElementId"),
+ pydantic.Field(alias="formElementId", description="The uniqueID of the Form element"),
+ ] = 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/form_submission_trigger_payload_schema_item.py b/src/webflow/types/form_submission_trigger_payload_schema_item.py
new file mode 100644
index 0000000..7550cfc
--- /dev/null
+++ b/src/webflow/types/form_submission_trigger_payload_schema_item.py
@@ -0,0 +1,36 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .form_submission_trigger_payload_schema_item_field_type import FormSubmissionTriggerPayloadSchemaItemFieldType
+
+
+class FormSubmissionTriggerPayloadSchemaItem(UniversalBaseModel):
+ field_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="fieldName"),
+ pydantic.Field(alias="fieldName", description="Form field name"),
+ ] = None
+ field_type: typing_extensions.Annotated[
+ typing.Optional[FormSubmissionTriggerPayloadSchemaItemFieldType],
+ FieldMetadata(alias="fieldType"),
+ pydantic.Field(alias="fieldType", description="Form field type"),
+ ] = None
+ field_element_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="fieldElementId"),
+ pydantic.Field(alias="fieldElementId", description="Element ID of the Form Field"),
+ ] = 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/form_submission_trigger_payload_schema_item_field_type.py b/src/webflow/types/form_submission_trigger_payload_schema_item_field_type.py
new file mode 100644
index 0000000..0ab97d1
--- /dev/null
+++ b/src/webflow/types/form_submission_trigger_payload_schema_item_field_type.py
@@ -0,0 +1,8 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+FormSubmissionTriggerPayloadSchemaItemFieldType = typing.Union[
+ typing.Literal["FormTextInput", "FormTextarea", "FormCheckboxInput", "FormRadioInput", "FormFileUploadInput"],
+ typing.Any,
+]
diff --git a/src/webflow/types/image_node.py b/src/webflow/types/image_node.py
index 019874c..56cf7cc 100644
--- a/src/webflow/types/image_node.py
+++ b/src/webflow/types/image_node.py
@@ -1,34 +1,37 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .image_node_image import ImageNodeImage
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class ImageNode(pydantic.BaseModel):
+class ImageNode(UniversalBaseModel):
"""
Represents an image within the DOM. It contains details about the image, such as its alternative text (alt) for accessibility and an asset identifier for fetching the actual image resource. Additional attributes can be associated with the image for styling or other purposes.
"""
- alt: typing.Optional[str] = None
- asset_id: typing.Optional[str] = pydantic.Field(alias="assetId", default=None)
+ id: str = pydantic.Field()
+ """
+ Node UUID
+ """
+
+ image: ImageNodeImage = pydantic.Field()
+ """
+ The image details of the node
+ """
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ attributes: typing.Optional[typing.Dict[str, str]] = pydantic.Field(default=None)
+ """
+ The custom attributes of the node
+ """
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/image_node_image.py b/src/webflow/types/image_node_image.py
new file mode 100644
index 0000000..1415afb
--- /dev/null
+++ b/src/webflow/types/image_node_image.py
@@ -0,0 +1,28 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+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"), pydantic.Field(alias="assetId")
+ ] = 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/invalid_scopes.py b/src/webflow/types/invalid_scopes.py
new file mode 100644
index 0000000..babfdd3
--- /dev/null
+++ b/src/webflow/types/invalid_scopes.py
@@ -0,0 +1,5 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+InvalidScopes = typing.Any
diff --git a/src/webflow/types/inventory_item.py b/src/webflow/types/inventory_item.py
index d1f66e9..5db3ff3 100644
--- a/src/webflow/types/inventory_item.py
+++ b/src/webflow/types/inventory_item.py
@@ -1,40 +1,40 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .inventory_item_inventory_type import InventoryItemInventoryType
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class InventoryItem(pydantic.BaseModel):
+class InventoryItem(UniversalBaseModel):
"""
The availabile inventory for an item
"""
- id: typing.Optional[str] = pydantic.Field(default=None, description="Unique identifier for a SKU item")
- quantity: typing.Optional[float] = pydantic.Field(
- default=None, description="Total quantity of items remaining in inventory (if inventoryType is finite)"
- )
- inventory_type: typing.Optional[InventoryItemInventoryType] = pydantic.Field(
- alias="inventoryType", default=None, description="infinite or finite"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Unique identifier for a SKU item
+ """
+
+ quantity: typing.Optional[float] = pydantic.Field(default=None)
+ """
+ Total quantity of items remaining in inventory (if inventoryType is finite)
+ """
+
+ inventory_type: typing_extensions.Annotated[
+ typing.Optional[InventoryItemInventoryType],
+ FieldMetadata(alias="inventoryType"),
+ pydantic.Field(alias="inventoryType", description="infinite or finite"),
+ ] = 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/inventory_item_inventory_type.py b/src/webflow/types/inventory_item_inventory_type.py
index a781e0c..bd5afd2 100644
--- a/src/webflow/types/inventory_item_inventory_type.py
+++ b/src/webflow/types/inventory_item_inventory_type.py
@@ -1,21 +1,5 @@
# This file was auto-generated by Fern from our API Definition.
-import enum
import typing
-T_Result = typing.TypeVar("T_Result")
-
-
-class InventoryItemInventoryType(str, enum.Enum):
- """
- infinite or finite
- """
-
- INFINITE = "infinite"
- FINITE = "finite"
-
- def visit(self, infinite: typing.Callable[[], T_Result], finite: typing.Callable[[], T_Result]) -> T_Result:
- if self is InventoryItemInventoryType.INFINITE:
- return infinite()
- if self is InventoryItemInventoryType.FINITE:
- return finite()
+InventoryItemInventoryType = typing.Union[typing.Literal["infinite", "finite"], typing.Any]
diff --git a/src/webflow/types/items_list_items_live_request_last_published.py b/src/webflow/types/items_list_items_live_request_last_published.py
new file mode 100644
index 0000000..ec7c86a
--- /dev/null
+++ b/src/webflow/types/items_list_items_live_request_last_published.py
@@ -0,0 +1,28 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class ItemsListItemsLiveRequestLastPublished(UniversalBaseModel):
+ lte: typing.Optional[dt.datetime] = pydantic.Field(default=None)
+ """
+ Filter items last published before this date
+ """
+
+ gte: typing.Optional[dt.datetime] = pydantic.Field(default=None)
+ """
+ Filter items last published after this date
+ """
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/items_list_items_request_last_published.py b/src/webflow/types/items_list_items_request_last_published.py
new file mode 100644
index 0000000..05dc5c2
--- /dev/null
+++ b/src/webflow/types/items_list_items_request_last_published.py
@@ -0,0 +1,28 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class ItemsListItemsRequestLastPublished(UniversalBaseModel):
+ lte: typing.Optional[dt.datetime] = pydantic.Field(default=None)
+ """
+ Filter items last published before this date
+ """
+
+ gte: typing.Optional[dt.datetime] = pydantic.Field(default=None)
+ """
+ Filter items last published after this date
+ """
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/list_custom_code_blocks.py b/src/webflow/types/list_custom_code_blocks.py
index 20ea276..9f5d58e 100644
--- a/src/webflow/types/list_custom_code_blocks.py
+++ b/src/webflow/types/list_custom_code_blocks.py
@@ -1,19 +1,14 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from .custom_code_block import CustomCodeBlock
from .pagination import Pagination
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class ListCustomCodeBlocks(pydantic.BaseModel):
+class ListCustomCodeBlocks(UniversalBaseModel):
"""
Custom Code Blocks corresponding to where scripts were applied
"""
@@ -21,15 +16,11 @@ class ListCustomCodeBlocks(pydantic.BaseModel):
blocks: typing.Optional[typing.List[CustomCodeBlock]] = None
pagination: typing.Optional[Pagination] = None
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/locale.py b/src/webflow/types/locale.py
new file mode 100644
index 0000000..19df91b
--- /dev/null
+++ b/src/webflow/types/locale.py
@@ -0,0 +1,61 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class Locale(UniversalBaseModel):
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The unique identifier for the locale.
+ """
+
+ cms_locale_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="cmsLocaleId"),
+ pydantic.Field(alias="cmsLocaleId", description="A CMS-specific identifier for the locale."),
+ ] = None
+ enabled: typing.Optional[bool] = pydantic.Field(default=None)
+ """
+ Indicates if the locale is enabled.
+ """
+
+ display_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="displayName"),
+ pydantic.Field(alias="displayName", description="The display name of the locale, typically in English."),
+ ] = None
+ display_image_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="displayImageId"),
+ pydantic.Field(
+ alias="displayImageId", description="An optional ID for an image associated with the locale, nullable."
+ ),
+ ] = None
+ redirect: typing.Optional[bool] = pydantic.Field(default=None)
+ """
+ Determines if requests should redirect to the locale's subdirectory.
+ """
+
+ subdirectory: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The subdirectory path for the locale, used in URLs.
+ """
+
+ tag: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ A tag or code representing the locale, often following a standard format like 'en-US'.
+ """
+
+ 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/locales.py b/src/webflow/types/locales.py
new file mode 100644
index 0000000..3d253a1
--- /dev/null
+++ b/src/webflow/types/locales.py
@@ -0,0 +1,28 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .locale import Locale
+
+
+class Locales(UniversalBaseModel):
+ primary: typing.Optional[Locale] = pydantic.Field(default=None)
+ """
+ The primary locale for the site or application.
+ """
+
+ secondary: typing.Optional[typing.List[Locale]] = pydantic.Field(default=None)
+ """
+ A list of secondary locales available for the site or application.
+ """
+
+ 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.py b/src/webflow/types/metadata.py
new file mode 100644
index 0000000..576efc7
--- /dev/null
+++ b/src/webflow/types/metadata.py
@@ -0,0 +1,27 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .metadata_options_item import MetadataOptionsItem
+
+
+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..5618523
--- /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.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+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/missing_scopes.py b/src/webflow/types/missing_scopes.py
deleted file mode 100644
index 74e0a7f..0000000
--- a/src/webflow/types/missing_scopes.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import datetime as dt
-import typing
-
-from ..core.datetime_utils import serialize_datetime
-from .error_details_item import ErrorDetailsItem
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class MissingScopes(pydantic.BaseModel):
- code: typing.Optional[typing.Literal["missing_scopes"]] = None
- type: typing.Optional[str] = None
- message: typing.Optional[str] = pydantic.Field(default=None, description="Error message")
- external_reference: typing.Optional[str] = pydantic.Field(
- alias="externalReference", default=None, description="Link to more information"
- )
- details: typing.Optional[typing.List[ErrorDetailsItem]] = pydantic.Field(
- default=None, description="Array of errors"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
diff --git a/src/webflow/types/new_order.py b/src/webflow/types/new_order.py
new file mode 100644
index 0000000..89296a7
--- /dev/null
+++ b/src/webflow/types/new_order.py
@@ -0,0 +1,31 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .order import Order
+
+
+class NewOrder(UniversalBaseModel):
+ """
+ The Webhook payload for when a new order is created
+ """
+
+ trigger_type: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="triggerType"),
+ pydantic.Field(alias="triggerType", description="The type of event that triggered the request"),
+ ] = None
+ payload: typing.Optional[Order] = 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/node.py b/src/webflow/types/node.py
index d15cf06..f413d08 100644
--- a/src/webflow/types/node.py
+++ b/src/webflow/types/node.py
@@ -1,39 +1,171 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
+from __future__ import annotations
+
import typing
-from ..core.datetime_utils import serialize_datetime
-from .image_node import ImageNode
-from .node_type import NodeType
-from .text_node import TextNode
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .component_property import ComponentProperty
+from .image_node_image import ImageNodeImage
+from .select_node_choices_item import SelectNodeChoicesItem
+from .text_node_text import TextNodeText
+
+
+class Node_Text(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"] = "text"
+ id: str
+ text: TextNodeText
+ 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_Image(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["image"] = "image"
+ id: str
+ image: ImageNodeImage
+ 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_ComponentInstance(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["component-instance"] = "component-instance"
+ id: str
+ component_id: typing_extensions.Annotated[
+ str, FieldMetadata(alias="componentId"), pydantic.Field(alias="componentId")
+ ]
+ property_overrides: typing_extensions.Annotated[
+ typing.List[ComponentProperty],
+ FieldMetadata(alias="propertyOverrides"),
+ pydantic.Field(alias="propertyOverrides"),
+ ]
+
+ 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
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+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: str
+ 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(pydantic.BaseModel):
+
+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.
"""
- id: typing.Optional[str] = pydantic.Field(default=None, description="Node UUID")
- type: typing.Optional[NodeType] = None
- text: typing.Optional[TextNode] = None
- image: typing.Optional[ImageNode] = None
+ type: typing.Literal["select"] = "select"
+ id: str
+ choices: typing.List[SelectNodeChoicesItem]
attributes: typing.Optional[typing.Dict[str, str]] = None
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ 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: str
+ value: str
+ waiting_text: typing_extensions.Annotated[
+ str, FieldMetadata(alias="waitingText"), pydantic.Field(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: str
+ 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
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
- class Config:
- frozen = True
- smart_union = True
- json_encoders = {dt.datetime: serialize_datetime}
+Node = typing_extensions.Annotated[
+ typing.Union[
+ Node_Text, Node_Image, Node_ComponentInstance, Node_TextInput, Node_Select, Node_SubmitButton, Node_SearchButton
+ ],
+ pydantic.Field(discriminator="type"),
+]
diff --git a/src/webflow/types/node_type.py b/src/webflow/types/node_type.py
deleted file mode 100644
index 943719c..0000000
--- a/src/webflow/types/node_type.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import enum
-import typing
-
-T_Result = typing.TypeVar("T_Result")
-
-
-class NodeType(str, enum.Enum):
- TEXT = "text"
- IMAGE = "image"
-
- def visit(self, text: typing.Callable[[], T_Result], image: typing.Callable[[], T_Result]) -> T_Result:
- if self is NodeType.TEXT:
- return text()
- if self is NodeType.IMAGE:
- return image()
diff --git a/src/webflow/types/not_enterprise_plan_site.py b/src/webflow/types/not_enterprise_plan_site.py
index 9c2c607..1001cf8 100644
--- a/src/webflow/types/not_enterprise_plan_site.py
+++ b/src/webflow/types/not_enterprise_plan_site.py
@@ -1,38 +1,5 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
-from .error_details_item import ErrorDetailsItem
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class NotEnterprisePlanSite(pydantic.BaseModel):
- code: typing.Optional[typing.Literal["missing_scopes"]] = None
- type: typing.Optional[str] = None
- message: typing.Optional[str] = pydantic.Field(default=None, description="Error message")
- external_reference: typing.Optional[str] = pydantic.Field(
- alias="externalReference", default=None, description="Link to more information"
- )
- details: typing.Optional[typing.List[ErrorDetailsItem]] = pydantic.Field(
- default=None, description="Array of errors"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+NotEnterprisePlanSite = typing.Any
diff --git a/src/webflow/types/not_enterprise_plan_workspace.py b/src/webflow/types/not_enterprise_plan_workspace.py
new file mode 100644
index 0000000..c945214
--- /dev/null
+++ b/src/webflow/types/not_enterprise_plan_workspace.py
@@ -0,0 +1,5 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+NotEnterprisePlanWorkspace = typing.Any
diff --git a/src/webflow/types/oauth_scope.py b/src/webflow/types/oauth_scope.py
index 2d49caa..1786f30 100644
--- a/src/webflow/types/oauth_scope.py
+++ b/src/webflow/types/oauth_scope.py
@@ -1,5 +1,3 @@
-# This file was auto-generated by Fern from our API Definition.
-
import enum
import typing
@@ -97,6 +95,26 @@ class OauthScope(str, enum.Enum):
modify users on the site
"""
+ WORKSPACE_READ = "workspace:read"
+ """
+ read workspace resource data
+ """
+
+ WORKSPACE_WRITE = "workspace:write"
+ """
+ write workspace resource data
+ """
+
+ SITE_CONFIG_READ= "site_config:read"
+ """
+ read site configuration data
+ """
+
+ SITE_CONFIG_WRITE= "site_config:write"
+ """
+ write site configuration data
+ """
+
def visit(
self,
authorized_user_read: typing.Callable[[], T_Result],
@@ -117,6 +135,10 @@ def visit(
users_read: typing.Callable[[], T_Result],
site_activity_read: typing.Callable[[], T_Result],
users_write: typing.Callable[[], T_Result],
+ workspace_read: typing.Callable[[], T_Result],
+ workspace_write: typing.Callable[[], T_Result],
+ site_config_read: typing.Callable[[], T_Result],
+ site_config_write: typing.Callable[[], T_Result],
) -> T_Result:
if self is OauthScope.AUTHORIZED_USER_READ:
return authorized_user_read()
@@ -154,3 +176,11 @@ def visit(
return site_activity_read()
if self is OauthScope.USERS_WRITE:
return users_write()
+ if self is OauthScope.WORKSPACE_READ:
+ return workspace_read()
+ if self is OauthScope.WORKSPACE_WRITE:
+ return workspace_write()
+ if self is OauthScope.SITE_CONFIG_READ:
+ return site_config_read()
+ if self is OauthScope.SITE_CONFIG_WRITE:
+ return site_config_write()
\ No newline at end of file
diff --git a/src/webflow/types/option_field.py b/src/webflow/types/option_field.py
new file mode 100644
index 0000000..ea1a98a
--- /dev/null
+++ b/src/webflow/types/option_field.py
@@ -0,0 +1,50 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .metadata import Metadata
+
+
+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(alias="isEditable", description="Define whether the field is editable"),
+ ] = None
+ is_required: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="isRequired"),
+ pydantic.Field(alias="isRequired", description="define whether a field is required in a collection"),
+ ] = None
+ 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(alias="displayName", description="The name of a field")
+ ]
+ help_text: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="helpText"),
+ pydantic.Field(alias="helpText", description="Additional text to help anyone filling out this field"),
+ ] = None
+ 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 9f7cdd6..56f1196 100644
--- a/src/webflow/types/order.py
+++ b/src/webflow/types/order.py
@@ -3,153 +3,226 @@
import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .order_address import OrderAddress
+from .order_billing_address import OrderBillingAddress
from .order_customer_info import OrderCustomerInfo
from .order_dispute_last_status import OrderDisputeLastStatus
from .order_download_files_item import OrderDownloadFilesItem
from .order_metadata import OrderMetadata
from .order_price import OrderPrice
from .order_purchased_item import OrderPurchasedItem
+from .order_shipping_address import OrderShippingAddress
from .order_status import OrderStatus
from .order_totals import OrderTotals
from .paypal_details import PaypalDetails
from .stripe_card import StripeCard
from .stripe_details import StripeDetails
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+class Order(UniversalBaseModel):
+ order_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="orderId"),
+ pydantic.Field(
+ alias="orderId",
+ description="The order ID. Will usually be 6 hex characters, but can also be 9\nhex characters if the site has a very large number of Orders.\nRandomly assigned.",
+ ),
+ ] = None
+ status: typing.Optional[OrderStatus] = pydantic.Field(default=None)
+ """
+ The status of the Order
+ """
-class Order(pydantic.BaseModel):
- order_id: typing.Optional[str] = pydantic.Field(
- alias="orderId",
- default=None,
- description="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.",
- )
- status: typing.Optional[OrderStatus] = pydantic.Field(default=None, description="The status of the Order")
- comment: typing.Optional[str] = pydantic.Field(
- default=None, description="A comment string for this Order editable by API user (not used by Webflow)."
- )
- order_comment: typing.Optional[str] = pydantic.Field(
- alias="orderComment", default=None, description="A comment that the customer left when making their Order"
- )
- accepted_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="acceptedOn", default=None, description="The ISO8601 timestamp that an Order was placed."
- )
- fulfilled_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="fulfilledOn",
- default=None,
- description="If an Order was marked as 'fulfilled', then this is the ISO8601 timestamp when that happened.",
- )
- refunded_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="refundedOn",
- default=None,
- description="If an Order was refunded, this is the ISO8601 of when that happened.",
- )
- disputed_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="disputedOn",
- default=None,
- description="If an Order was disputed by the customer, then this key will be set with the ISO8601 timestamp that Stripe notifies Webflow. Null if not disputed.",
- )
- dispute_updated_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="disputeUpdatedOn",
- default=None,
- description="If an Order was disputed by the customer, then this key will be set with the ISO8601 timestamp of the last time that we got an update. Null if not disputed.",
- )
- dispute_last_status: typing.Optional[OrderDisputeLastStatus] = pydantic.Field(
- alias="disputeLastStatus",
- default=None,
- description="If an order was disputed by the customer, then this key will be set with the [dispute's status](https://stripe.com/docs/api#dispute_object-status).",
- )
- customer_paid: typing.Optional[OrderPrice] = pydantic.Field(
- alias="customerPaid", default=None, description="The total paid by the customer"
- )
- net_amount: typing.Optional[OrderPrice] = pydantic.Field(
- alias="netAmount", default=None, description="The net amount after application fees"
- )
- application_fee: typing.Optional[OrderPrice] = pydantic.Field(
- alias="applicationFee", default=None, description="The application fee assessed by the platform"
- )
- all_addresses: typing.Optional[typing.List[OrderAddress]] = pydantic.Field(
- alias="allAddresses",
- default=None,
- description="All addresses provided by the customer during the ordering flow.",
- )
- shipping_address: typing.Optional[OrderAddress] = pydantic.Field(
- alias="shippingAddress", default=None, description="The shipping address"
- )
- billing_address: typing.Optional[OrderAddress] = pydantic.Field(
- alias="billingAddress", default=None, description="The billing address"
- )
- shipping_provider: typing.Optional[str] = pydantic.Field(
- alias="shippingProvider",
- default=None,
- description="A string editable by the API user to note the shipping provider used (not used by Webflow).",
- )
- shipping_tracking: typing.Optional[str] = pydantic.Field(
- alias="shippingTracking",
- default=None,
- description="A string editable by the API user to note the shipping tracking number for the order (not used by Webflow).",
- )
- shipping_tracking_url: typing.Optional[str] = pydantic.Field(alias="shippingTrackingURL", default=None)
- customer_info: typing.Optional[OrderCustomerInfo] = pydantic.Field(
- alias="customerInfo", default=None, description="An object with the keys `fullName` and `email`."
- )
- purchased_items: typing.Optional[typing.List[OrderPurchasedItem]] = pydantic.Field(
- alias="purchasedItems", default=None, description="An array of all things that the Customer purchased."
- )
- purchased_items_count: typing.Optional[float] = pydantic.Field(
- alias="purchasedItemsCount", default=None, description="The sum of all 'count' fields in 'purchasedItems'."
- )
- stripe_details: typing.Optional[StripeDetails] = pydantic.Field(alias="stripeDetails", default=None)
- stripe_card: typing.Optional[StripeCard] = pydantic.Field(alias="stripeCard", default=None)
- paypal_details: typing.Optional[PaypalDetails] = pydantic.Field(alias="paypalDetails", default=None)
- custom_data: typing.Optional[typing.List[typing.Dict[str, typing.Any]]] = pydantic.Field(
- alias="customData",
- default=None,
- description="An array of additional inputs for custom order data gathering. Each object in the array represents an input with a name, and a textInput, textArea, or checkbox value.",
- )
+ comment: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ A comment string for this Order, which is editable by API user (not used by Webflow).
+ """
+
+ order_comment: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="orderComment"),
+ pydantic.Field(alias="orderComment", description="A comment that the customer left when making their Order"),
+ ] = None
+ accepted_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="acceptedOn"),
+ pydantic.Field(alias="acceptedOn", description="The ISO8601 timestamp that an Order was placed."),
+ ] = None
+ fulfilled_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="fulfilledOn"),
+ pydantic.Field(
+ alias="fulfilledOn",
+ description="When an Order is marked as 'fulfilled', this field represents the timestamp of the fulfillment in ISO8601 format. Otherwise, it is null.",
+ ),
+ ] = None
+ refunded_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="refundedOn"),
+ pydantic.Field(
+ alias="refundedOn",
+ description="When an Order is marked as 'refunded', this field represents the timestamp of the fulfillment in ISO8601 format. Otherwise, it is null.",
+ ),
+ ] = None
+ disputed_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="disputedOn"),
+ pydantic.Field(
+ alias="disputedOn",
+ description="When an Order is marked as 'disputed', this field represents the timestamp of the fulfillment in ISO8601 format. Otherwise, it is null.",
+ ),
+ ] = None
+ dispute_updated_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="disputeUpdatedOn"),
+ pydantic.Field(
+ alias="disputeUpdatedOn",
+ description="If an Order has been disputed by the customer, this key will be set to the ISO8601 timestamp of the last update received. If the Order is not disputed, the key will be null.",
+ ),
+ ] = None
+ dispute_last_status: typing_extensions.Annotated[
+ typing.Optional[OrderDisputeLastStatus],
+ FieldMetadata(alias="disputeLastStatus"),
+ pydantic.Field(
+ alias="disputeLastStatus",
+ description="If an order was disputed by the customer, then this key will be set with the [dispute's status](https://stripe.com/docs/api#dispute_object-status).",
+ ),
+ ] = None
+ customer_paid: typing_extensions.Annotated[
+ typing.Optional[OrderPrice],
+ FieldMetadata(alias="customerPaid"),
+ pydantic.Field(alias="customerPaid", description="The total paid by the customer"),
+ ] = None
+ net_amount: typing_extensions.Annotated[
+ typing.Optional[OrderPrice],
+ FieldMetadata(alias="netAmount"),
+ pydantic.Field(alias="netAmount", description="The net amount after application fees"),
+ ] = None
+ application_fee: typing_extensions.Annotated[
+ typing.Optional[OrderPrice],
+ FieldMetadata(alias="applicationFee"),
+ pydantic.Field(alias="applicationFee", description="The application fee assessed by the platform"),
+ ] = None
+ all_addresses: typing_extensions.Annotated[
+ typing.Optional[typing.List[OrderAddress]],
+ FieldMetadata(alias="allAddresses"),
+ pydantic.Field(
+ alias="allAddresses", description="All addresses provided by the customer during the ordering flow."
+ ),
+ ] = None
+ shipping_address: typing_extensions.Annotated[
+ typing.Optional[OrderShippingAddress],
+ FieldMetadata(alias="shippingAddress"),
+ pydantic.Field(alias="shippingAddress", description="The shipping address"),
+ ] = None
+ billing_address: typing_extensions.Annotated[
+ typing.Optional[OrderBillingAddress],
+ FieldMetadata(alias="billingAddress"),
+ pydantic.Field(alias="billingAddress", description="The billing address"),
+ ] = None
+ shipping_provider: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="shippingProvider"),
+ pydantic.Field(
+ alias="shippingProvider",
+ description="A string editable by the API user to note the shipping provider used (not used by Webflow).",
+ ),
+ ] = None
+ shipping_tracking: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="shippingTracking"),
+ pydantic.Field(
+ alias="shippingTracking",
+ description="A string editable by the API user to note the shipping tracking number for the order (not used by Webflow).",
+ ),
+ ] = None
+ shipping_tracking_url: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="shippingTrackingURL"), pydantic.Field(alias="shippingTrackingURL")
+ ] = None
+ customer_info: typing_extensions.Annotated[
+ typing.Optional[OrderCustomerInfo],
+ FieldMetadata(alias="customerInfo"),
+ pydantic.Field(alias="customerInfo", description="An object with the keys `fullName` and `email`."),
+ ] = None
+ purchased_items: typing_extensions.Annotated[
+ typing.Optional[typing.List[OrderPurchasedItem]],
+ FieldMetadata(alias="purchasedItems"),
+ pydantic.Field(alias="purchasedItems", description="An array of all things that the Customer purchased."),
+ ] = None
+ purchased_items_count: typing_extensions.Annotated[
+ typing.Optional[float],
+ FieldMetadata(alias="purchasedItemsCount"),
+ pydantic.Field(alias="purchasedItemsCount", description="The sum of all 'count' fields in 'purchasedItems'."),
+ ] = None
+ stripe_details: typing_extensions.Annotated[
+ typing.Optional[StripeDetails], FieldMetadata(alias="stripeDetails"), pydantic.Field(alias="stripeDetails")
+ ] = None
+ stripe_card: typing_extensions.Annotated[
+ typing.Optional[StripeCard], FieldMetadata(alias="stripeCard"), pydantic.Field(alias="stripeCard")
+ ] = None
+ paypal_details: typing_extensions.Annotated[
+ typing.Optional[PaypalDetails], FieldMetadata(alias="paypalDetails"), pydantic.Field(alias="paypalDetails")
+ ] = None
+ custom_data: typing_extensions.Annotated[
+ typing.Optional[typing.List[typing.Dict[str, typing.Any]]],
+ FieldMetadata(alias="customData"),
+ pydantic.Field(
+ alias="customData",
+ description="An array of additional inputs for custom order data gathering. Each object in the array represents an input with a name, and a textInput, textArea, or checkbox value.",
+ ),
+ ] = None
metadata: typing.Optional[OrderMetadata] = None
- is_customer_deleted: typing.Optional[bool] = pydantic.Field(
- alias="isCustomerDeleted",
- default=None,
- description="A boolean indicating whether the customer has been deleted from the site.",
- )
- is_shipping_required: typing.Optional[bool] = pydantic.Field(
- alias="isShippingRequired",
- default=None,
- description="A boolean indicating whether the order contains one or more purchased items that require shipping.",
- )
- has_downloads: typing.Optional[bool] = pydantic.Field(
- alias="hasDownloads",
- default=None,
- description="A boolean indicating whether the order contains one or more purchased items that are downloadable.",
- )
- payment_processor: typing.Optional[str] = pydantic.Field(
- alias="paymentProcessor",
- default=None,
- description="A string indicating the payment processor used for this order.",
- )
- totals: typing.Optional[OrderTotals] = pydantic.Field(
- default=None, description="An object describing various pricing totals"
- )
- download_files: typing.Optional[typing.List[OrderDownloadFilesItem]] = pydantic.Field(
- alias="downloadFiles", default=None, description="An array of downloadable file objects."
- )
+ is_customer_deleted: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="isCustomerDeleted"),
+ pydantic.Field(
+ alias="isCustomerDeleted",
+ description="A boolean indicating whether the customer has been deleted from the site.",
+ ),
+ ] = None
+ is_shipping_required: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="isShippingRequired"),
+ pydantic.Field(
+ alias="isShippingRequired",
+ description="A boolean indicating whether the order contains one or more purchased items that require shipping.",
+ ),
+ ] = None
+ has_downloads: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="hasDownloads"),
+ pydantic.Field(
+ alias="hasDownloads",
+ description="A boolean indicating whether the order contains one or more purchased items that are downloadable.",
+ ),
+ ] = None
+ payment_processor: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="paymentProcessor"),
+ pydantic.Field(
+ alias="paymentProcessor", description="A string indicating the payment processor used for this order."
+ ),
+ ] = None
+ totals: typing.Optional[OrderTotals] = pydantic.Field(default=None)
+ """
+ An object describing various pricing totals
+ """
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ download_files: typing_extensions.Annotated[
+ typing.Optional[typing.List[OrderDownloadFilesItem]],
+ FieldMetadata(alias="downloadFiles"),
+ pydantic.Field(alias="downloadFiles", description="An array of downloadable file objects."),
+ ] = None
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/order_address.py b/src/webflow/types/order_address.py
index a22a3de..ad31ad4 100644
--- a/src/webflow/types/order_address.py
+++ b/src/webflow/types/order_address.py
@@ -1,53 +1,74 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .order_address_japan_type import OrderAddressJapanType
from .order_address_type import OrderAddressType
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class OrderAddress(pydantic.BaseModel):
+class OrderAddress(UniversalBaseModel):
"""
A customer address
"""
- type: typing.Optional[OrderAddressType] = pydantic.Field(
- default=None, description="The type of the order address (billing or shipping)"
- )
- japan_type: typing.Optional[OrderAddressJapanType] = pydantic.Field(
- alias="japanType", default=None, description="Japan-only address format"
- )
- addressee: typing.Optional[str] = pydantic.Field(default=None, description="Display name on the address")
- line_1: typing.Optional[str] = pydantic.Field(
- alias="line1", default=None, description="The first line of the address"
- )
- line_2: typing.Optional[str] = pydantic.Field(
- alias="line2", default=None, description="The second line of the address"
- )
- city: typing.Optional[str] = pydantic.Field(default=None, description="The city of the address.")
- state: typing.Optional[str] = pydantic.Field(default=None, description="The state or province of the address")
- country: typing.Optional[str] = pydantic.Field(default=None, description="The country of the address")
- postal_code: typing.Optional[str] = pydantic.Field(
- alias="postalCode", default=None, description="The postal code of the address"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ type: typing.Optional[OrderAddressType] = pydantic.Field(default=None)
+ """
+ The type of the order address (billing or shipping)
+ """
+
+ japan_type: typing_extensions.Annotated[
+ typing.Optional[OrderAddressJapanType],
+ FieldMetadata(alias="japanType"),
+ pydantic.Field(
+ alias="japanType",
+ description="Represents a Japan-only address format. This field will only appear on orders placed from Japan.",
+ ),
+ ] = None
+ 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(alias="line1", description="The first line of the address"),
+ ] = None
+ line_2: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="line2"),
+ pydantic.Field(alias="line2", description="The second line of the address"),
+ ] = None
+ 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(alias="postalCode", description="The postal code of the address"),
+ ] = 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/order_address_japan_type.py b/src/webflow/types/order_address_japan_type.py
index 053942b..f3f1936 100644
--- a/src/webflow/types/order_address_japan_type.py
+++ b/src/webflow/types/order_address_japan_type.py
@@ -1,21 +1,5 @@
# This file was auto-generated by Fern from our API Definition.
-import enum
import typing
-T_Result = typing.TypeVar("T_Result")
-
-
-class OrderAddressJapanType(str, enum.Enum):
- """
- Japan-only address format
- """
-
- KANA = "kana"
- KANJI = "kanji"
-
- def visit(self, kana: typing.Callable[[], T_Result], kanji: typing.Callable[[], T_Result]) -> T_Result:
- if self is OrderAddressJapanType.KANA:
- return kana()
- if self is OrderAddressJapanType.KANJI:
- return kanji()
+OrderAddressJapanType = typing.Union[typing.Literal["kana", "kanji"], typing.Any]
diff --git a/src/webflow/types/order_address_type.py b/src/webflow/types/order_address_type.py
index c54193a..a53b554 100644
--- a/src/webflow/types/order_address_type.py
+++ b/src/webflow/types/order_address_type.py
@@ -1,21 +1,5 @@
# This file was auto-generated by Fern from our API Definition.
-import enum
import typing
-T_Result = typing.TypeVar("T_Result")
-
-
-class OrderAddressType(str, enum.Enum):
- """
- The type of the order address (billing or shipping)
- """
-
- SHIPPING = "shipping"
- BILLING = "billing"
-
- def visit(self, shipping: typing.Callable[[], T_Result], billing: typing.Callable[[], T_Result]) -> T_Result:
- if self is OrderAddressType.SHIPPING:
- return shipping()
- if self is OrderAddressType.BILLING:
- return billing()
+OrderAddressType = typing.Union[typing.Literal["shipping", "billing"], typing.Any]
diff --git a/src/webflow/types/order_billing_address.py b/src/webflow/types/order_billing_address.py
new file mode 100644
index 0000000..484d367
--- /dev/null
+++ b/src/webflow/types/order_billing_address.py
@@ -0,0 +1,74 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .order_billing_address_japan_type import OrderBillingAddressJapanType
+from .order_billing_address_type import OrderBillingAddressType
+
+
+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(
+ alias="japanType",
+ description="Represents a Japan-only address format. This field will only appear on orders placed from Japan.",
+ ),
+ ] = None
+ 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(alias="line1", description="The first line of the address"),
+ ] = None
+ line_2: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="line2"),
+ pydantic.Field(alias="line2", description="The second line of the address"),
+ ] = None
+ 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(alias="postalCode", description="The postal code of the address"),
+ ] = 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/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_customer_info.py b/src/webflow/types/order_customer_info.py
index e0486d2..fe7d88c 100644
--- a/src/webflow/types/order_customer_info.py
+++ b/src/webflow/types/order_customer_info.py
@@ -1,36 +1,33 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class OrderCustomerInfo(pydantic.BaseModel):
+class OrderCustomerInfo(UniversalBaseModel):
"""
An object with the keys `fullName` and `email`.
"""
- full_name: typing.Optional[str] = pydantic.Field(
- alias="fullName", default=None, description="The full name of the Customer"
- )
- email: typing.Optional[str] = pydantic.Field(default=None, description="The Customer's email address")
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ full_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="fullName"),
+ pydantic.Field(alias="fullName", description="The full name of the Customer"),
+ ] = None
+ email: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The Customer's email address
+ """
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/order_dispute_last_status.py b/src/webflow/types/order_dispute_last_status.py
index cc88362..16c3ae0 100644
--- a/src/webflow/types/order_dispute_last_status.py
+++ b/src/webflow/types/order_dispute_last_status.py
@@ -1,49 +1,17 @@
# This file was auto-generated by Fern from our API Definition.
-import enum
import typing
-T_Result = typing.TypeVar("T_Result")
-
-
-class OrderDisputeLastStatus(str, enum.Enum):
- """
- If an order was disputed by the customer, then this key will be set with the [dispute's status](https://stripe.com/docs/api#dispute_object-status).
- """
-
- WARNING_NEEDS_RESPONSE = "warning_needs_response"
- WARNING_UNDER_REVIEW = "warning_under_review"
- WARNING_CLOSED = "warning_closed"
- NEEDS_RESPONSE = "needs_response"
- UNDER_REVIEW = "under_review"
- CHARGE_REFUNDED = "charge_refunded"
- WON = "won"
- LOST = "lost"
-
- def visit(
- self,
- warning_needs_response: typing.Callable[[], T_Result],
- warning_under_review: typing.Callable[[], T_Result],
- warning_closed: typing.Callable[[], T_Result],
- needs_response: typing.Callable[[], T_Result],
- under_review: typing.Callable[[], T_Result],
- charge_refunded: typing.Callable[[], T_Result],
- won: typing.Callable[[], T_Result],
- lost: typing.Callable[[], T_Result],
- ) -> T_Result:
- if self is OrderDisputeLastStatus.WARNING_NEEDS_RESPONSE:
- return warning_needs_response()
- if self is OrderDisputeLastStatus.WARNING_UNDER_REVIEW:
- return warning_under_review()
- if self is OrderDisputeLastStatus.WARNING_CLOSED:
- return warning_closed()
- if self is OrderDisputeLastStatus.NEEDS_RESPONSE:
- return needs_response()
- if self is OrderDisputeLastStatus.UNDER_REVIEW:
- return under_review()
- if self is OrderDisputeLastStatus.CHARGE_REFUNDED:
- return charge_refunded()
- if self is OrderDisputeLastStatus.WON:
- return won()
- if self is OrderDisputeLastStatus.LOST:
- return lost()
+OrderDisputeLastStatus = typing.Union[
+ typing.Literal[
+ "warning_needs_response",
+ "warning_under_review",
+ "warning_closed",
+ "needs_response",
+ "under_review",
+ "charge_refunded",
+ "won",
+ "lost",
+ ],
+ typing.Any,
+]
diff --git a/src/webflow/types/order_download_files_item.py b/src/webflow/types/order_download_files_item.py
index 15a3210..1b54068 100644
--- a/src/webflow/types/order_download_files_item.py
+++ b/src/webflow/types/order_download_files_item.py
@@ -1,36 +1,32 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class OrderDownloadFilesItem(pydantic.BaseModel):
- id: typing.Optional[str] = pydantic.Field(
- default=None, description="The unique identifier for the downloadable file"
- )
- name: typing.Optional[str] = pydantic.Field(
- default=None, description="The user-facing name for the downloadable file"
- )
- url: typing.Optional[str] = pydantic.Field(
- default=None, description="The hosted location for the downloadable file"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- json_encoders = {dt.datetime: serialize_datetime}
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class OrderDownloadFilesItem(UniversalBaseModel):
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The unique identifier for the downloadable file
+ """
+
+ name: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The user-facing name for the downloadable file
+ """
+
+ url: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The hosted location for the downloadable file
+ """
+
+ 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_list.py b/src/webflow/types/order_list.py
index 2ad1b84..2ecc568 100644
--- a/src/webflow/types/order_list.py
+++ b/src/webflow/types/order_list.py
@@ -1,35 +1,30 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from .order import Order
from .pagination import Pagination
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class OrderList(pydantic.BaseModel):
+class OrderList(UniversalBaseModel):
"""
Results from order list
"""
- items: typing.Optional[typing.List[Order]] = pydantic.Field(default=None, description="List of orders")
- pagination: typing.Optional[Pagination] = None
+ orders: typing.Optional[typing.List[Order]] = pydantic.Field(default=None)
+ """
+ List of orders
+ """
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ pagination: typing.Optional[Pagination] = None
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/order_metadata.py b/src/webflow/types/order_metadata.py
index d37fc38..33d966b 100644
--- a/src/webflow/types/order_metadata.py
+++ b/src/webflow/types/order_metadata.py
@@ -1,29 +1,23 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+class OrderMetadata(UniversalBaseModel):
+ is_buy_now: typing_extensions.Annotated[
+ typing.Optional[bool], FieldMetadata(alias="isBuyNow"), pydantic.Field(alias="isBuyNow")
+ ] = None
-class OrderMetadata(pydantic.BaseModel):
- is_buy_now: typing.Optional[bool] = pydantic.Field(alias="isBuyNow", default=None)
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/order_price.py b/src/webflow/types/order_price.py
index 36012d1..310ea28 100644
--- a/src/webflow/types/order_price.py
+++ b/src/webflow/types/order_price.py
@@ -1,34 +1,32 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+class OrderPrice(UniversalBaseModel):
+ unit: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The three-letter ISO currency code
+ """
-class OrderPrice(pydantic.BaseModel):
- unit: typing.Optional[str] = pydantic.Field(default=None, description="The three-letter ISO currency code")
- value: typing.Optional[str] = pydantic.Field(
- default=None, description="The numeric value in the base unit of the currency"
- )
- string: typing.Optional[str] = pydantic.Field(
- default=None, description="The user-facing string representation of the amount"
- )
+ value: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The numeric value in the base unit of the currency
+ """
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ string: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The user-facing string representation of the amount
+ """
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/order_purchased_item.py b/src/webflow/types/order_purchased_item.py
index f2250aa..01b815e 100644
--- a/src/webflow/types/order_purchased_item.py
+++ b/src/webflow/types/order_purchased_item.py
@@ -1,72 +1,100 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .order_price import OrderPrice
from .order_purchased_item_variant_image import OrderPurchasedItemVariantImage
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class OrderPurchasedItem(pydantic.BaseModel):
+class OrderPurchasedItem(UniversalBaseModel):
"""
An Item that was purchased
"""
- count: typing.Optional[float] = pydantic.Field(default=None, description="Number of Item purchased.")
- row_total: typing.Optional[OrderPrice] = pydantic.Field(
- alias="rowTotal", default=None, description="The total for the row"
- )
- product_id: typing.Optional[str] = pydantic.Field(
- alias="productId", default=None, description="The unique identifier for the Product"
- )
- product_name: typing.Optional[str] = pydantic.Field(
- alias="productName", default=None, description="User-facing name of the Product"
- )
- product_slug: typing.Optional[str] = pydantic.Field(
- alias="productSlug", default=None, description="Slug for the Product"
- )
- variant_id: typing.Optional[str] = pydantic.Field(
- alias="variantId", default=None, description="Identifier for the Product Variant (SKU)"
- )
- variant_name: typing.Optional[str] = pydantic.Field(
- alias="variantName", default=None, description="User-facing name of the Product Variant (SKU)"
- )
- variant_slug: typing.Optional[str] = pydantic.Field(
- alias="variantSlug", default=None, description="Slug for the Product Variant (SKU)"
- )
- variant_image: typing.Optional[OrderPurchasedItemVariantImage] = pydantic.Field(alias="variantImage", default=None)
- variant_price: typing.Optional[OrderPrice] = pydantic.Field(
- alias="variantPrice", default=None, description="The price corresponding to the variant"
- )
- weight: typing.Optional[float] = pydantic.Field(
- default=None, description="The physical weight of the variant if provided, or null"
- )
- width: typing.Optional[float] = pydantic.Field(
- default=None, description="The physical width of the variant if provided, or null"
- )
- height: typing.Optional[float] = pydantic.Field(
- default=None, description="The physical height of the variant if provided, or null"
- )
- length: typing.Optional[float] = pydantic.Field(
- default=None, description="The physical length of the variant if provided, or null"
- )
+ count: typing.Optional[float] = pydantic.Field(default=None)
+ """
+ Number of Item purchased.
+ """
+
+ row_total: typing_extensions.Annotated[
+ typing.Optional[OrderPrice],
+ FieldMetadata(alias="rowTotal"),
+ pydantic.Field(alias="rowTotal", description="The total for the row"),
+ ] = None
+ product_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="productId"),
+ pydantic.Field(alias="productId", description="The unique identifier for the Product"),
+ ] = None
+ product_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="productName"),
+ pydantic.Field(alias="productName", description="User-facing name of the Product"),
+ ] = None
+ product_slug: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="productSlug"),
+ pydantic.Field(alias="productSlug", description="Slug for the Product"),
+ ] = None
+ variant_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="variantId"),
+ pydantic.Field(alias="variantId", description="Identifier for the Product Variant (SKU)"),
+ ] = None
+ variant_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="variantName"),
+ pydantic.Field(alias="variantName", description="User-facing name of the Product Variant (SKU)"),
+ ] = None
+ variant_slug: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="variantSlug"),
+ pydantic.Field(alias="variantSlug", description="Slug for the Product Variant (SKU)"),
+ ] = None
+ variant_sku: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="variantSKU"),
+ pydantic.Field(alias="variantSKU", description="The user-defined custom SKU of the Product Variant (SKU)"),
+ ] = None
+ variant_image: typing_extensions.Annotated[
+ typing.Optional[OrderPurchasedItemVariantImage],
+ FieldMetadata(alias="variantImage"),
+ pydantic.Field(alias="variantImage"),
+ ] = None
+ variant_price: typing_extensions.Annotated[
+ typing.Optional[OrderPrice],
+ FieldMetadata(alias="variantPrice"),
+ pydantic.Field(alias="variantPrice", description="The price corresponding to the variant"),
+ ] = None
+ weight: typing.Optional[float] = pydantic.Field(default=None)
+ """
+ The physical weight of the variant if provided, or null
+ """
+
+ width: typing.Optional[float] = pydantic.Field(default=None)
+ """
+ The physical width of the variant if provided, or null
+ """
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ height: typing.Optional[float] = pydantic.Field(default=None)
+ """
+ The physical height of the variant if provided, or null
+ """
+
+ length: typing.Optional[float] = pydantic.Field(default=None)
+ """
+ The physical length of the variant if provided, or null
+ """
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/order_purchased_item_variant_image.py b/src/webflow/types/order_purchased_item_variant_image.py
index 0b31d99..14b745f 100644
--- a/src/webflow/types/order_purchased_item_variant_image.py
+++ b/src/webflow/types/order_purchased_item_variant_image.py
@@ -1,30 +1,25 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from .order_purchased_item_variant_image_file import OrderPurchasedItemVariantImageFile
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+class OrderPurchasedItemVariantImage(UniversalBaseModel):
+ url: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The hosted location for the Variant's image
+ """
-class OrderPurchasedItemVariantImage(pydantic.BaseModel):
- url: typing.Optional[str] = pydantic.Field(default=None, description="The hosted location for the Variant's image")
file: typing.Optional[OrderPurchasedItemVariantImageFile] = None
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/order_purchased_item_variant_image_file.py b/src/webflow/types/order_purchased_item_variant_image_file.py
index 9d73a2d..0dc2670 100644
--- a/src/webflow/types/order_purchased_item_variant_image_file.py
+++ b/src/webflow/types/order_purchased_item_variant_image_file.py
@@ -3,42 +3,56 @@
import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .order_purchased_item_variant_image_file_variants_item import OrderPurchasedItemVariantImageFileVariantsItem
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+class OrderPurchasedItemVariantImageFile(UniversalBaseModel):
+ size: typing.Optional[float] = pydantic.Field(default=None)
+ """
+ The image size in bytes
+ """
+
+ original_file_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="originalFileName"),
+ pydantic.Field(alias="originalFileName", description="the original name of the image"),
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="The creation timestamp of the image"),
+ ] = None
+ content_type: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="contentType"),
+ pydantic.Field(alias="contentType", description="The MIME type of the image"),
+ ] = None
+ width: typing.Optional[int] = pydantic.Field(default=None)
+ """
+ The image width in pixels
+ """
+
+ height: typing.Optional[int] = pydantic.Field(default=None)
+ """
+ The image height in pixels
+ """
-class OrderPurchasedItemVariantImageFile(pydantic.BaseModel):
- size: typing.Optional[float] = pydantic.Field(default=None, description="The image size in bytes")
- original_file_name: typing.Optional[str] = pydantic.Field(
- alias="originalFileName", default=None, description="the original name of the image"
- )
- created_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="createdOn", default=None, description="The creation timestamp of the image"
- )
- content_type: typing.Optional[str] = pydantic.Field(
- alias="contentType", default=None, description="The MIME type of the image"
- )
- width: typing.Optional[int] = pydantic.Field(default=None, description="The image width in pixels")
- height: typing.Optional[int] = pydantic.Field(default=None, description="The image height in pixels")
variants: typing.Optional[typing.List[OrderPurchasedItemVariantImageFileVariantsItem]] = pydantic.Field(
- default=None, description="Variants of the supplied image"
+ default=None
)
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ """
+ Variants of the supplied image
+ """
+
+ 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_purchased_item_variant_image_file_variants_item.py b/src/webflow/types/order_purchased_item_variant_image_file_variants_item.py
index fc37a0d..093c7df 100644
--- a/src/webflow/types/order_purchased_item_variant_image_file_variants_item.py
+++ b/src/webflow/types/order_purchased_item_variant_image_file_variants_item.py
@@ -1,33 +1,42 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class OrderPurchasedItemVariantImageFileVariantsItem(pydantic.BaseModel):
- url: typing.Optional[str] = pydantic.Field(default=None, description="The hosted location for the Variant's image")
- original_file_name: typing.Optional[str] = pydantic.Field(alias="originalFileName", default=None)
- size: typing.Optional[float] = pydantic.Field(default=None, description="The image size in bytes")
- width: typing.Optional[int] = pydantic.Field(default=None, description="The image width in pixels")
- height: typing.Optional[int] = pydantic.Field(default=None, description="The image height in pixels")
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class OrderPurchasedItemVariantImageFileVariantsItem(UniversalBaseModel):
+ url: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The hosted location for the Variant's image
+ """
+
+ original_file_name: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="originalFileName"), pydantic.Field(alias="originalFileName")
+ ] = None
+ size: typing.Optional[float] = pydantic.Field(default=None)
+ """
+ The image size in bytes
+ """
+
+ width: typing.Optional[int] = pydantic.Field(default=None)
+ """
+ The image width in pixels
+ """
+
+ height: typing.Optional[int] = pydantic.Field(default=None)
+ """
+ The image height in pixels
+ """
+
+ 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.py b/src/webflow/types/order_shipping_address.py
new file mode 100644
index 0000000..afa230a
--- /dev/null
+++ b/src/webflow/types/order_shipping_address.py
@@ -0,0 +1,74 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .order_shipping_address_japan_type import OrderShippingAddressJapanType
+from .order_shipping_address_type import OrderShippingAddressType
+
+
+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(
+ alias="japanType",
+ description="Represents a Japan-only address format. This field will only appear on orders placed from Japan.",
+ ),
+ ] = None
+ 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(alias="line1", description="The first line of the address"),
+ ] = None
+ line_2: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="line2"),
+ pydantic.Field(alias="line2", description="The second line of the address"),
+ ] = None
+ 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(alias="postalCode", description="The postal code of the address"),
+ ] = 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/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/order_status.py b/src/webflow/types/order_status.py
index 8db83e5..58e235c 100644
--- a/src/webflow/types/order_status.py
+++ b/src/webflow/types/order_status.py
@@ -1,41 +1,7 @@
# This file was auto-generated by Fern from our API Definition.
-import enum
import typing
-T_Result = typing.TypeVar("T_Result")
-
-
-class OrderStatus(str, enum.Enum):
- """
- The status of the Order
- """
-
- PENDING = "pending"
- UNFULFILLED = "unfulfilled"
- FULFILLED = "fulfilled"
- DISPUTED = "disputed"
- DISPUTE_LOST = "dispute-lost"
- REFUNDED = "refunded"
-
- def visit(
- self,
- pending: typing.Callable[[], T_Result],
- unfulfilled: typing.Callable[[], T_Result],
- fulfilled: typing.Callable[[], T_Result],
- disputed: typing.Callable[[], T_Result],
- dispute_lost: typing.Callable[[], T_Result],
- refunded: typing.Callable[[], T_Result],
- ) -> T_Result:
- if self is OrderStatus.PENDING:
- return pending()
- if self is OrderStatus.UNFULFILLED:
- return unfulfilled()
- if self is OrderStatus.FULFILLED:
- return fulfilled()
- if self is OrderStatus.DISPUTED:
- return disputed()
- if self is OrderStatus.DISPUTE_LOST:
- return dispute_lost()
- if self is OrderStatus.REFUNDED:
- return refunded()
+OrderStatus = typing.Union[
+ typing.Literal["pending", "unfulfilled", "fulfilled", "disputed", "dispute-lost", "refunded"], typing.Any
+]
diff --git a/src/webflow/types/order_totals.py b/src/webflow/types/order_totals.py
index ef88075..deca73c 100644
--- a/src/webflow/types/order_totals.py
+++ b/src/webflow/types/order_totals.py
@@ -1,38 +1,38 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from .order_price import OrderPrice
from .order_totals_extras_item import OrderTotalsExtrasItem
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class OrderTotals(pydantic.BaseModel):
+class OrderTotals(UniversalBaseModel):
"""
An object describing various pricing totals
"""
- subtotal: typing.Optional[OrderPrice] = pydantic.Field(default=None, description="The subtotal price")
- extras: typing.Optional[typing.List[OrderTotalsExtrasItem]] = pydantic.Field(
- default=None, description="An array of extra items, includes discounts, shipping, and taxes."
- )
- total: typing.Optional[OrderPrice] = pydantic.Field(default=None, description="The total price")
+ subtotal: typing.Optional[OrderPrice] = pydantic.Field(default=None)
+ """
+ The subtotal price
+ """
+
+ extras: typing.Optional[typing.List[OrderTotalsExtrasItem]] = pydantic.Field(default=None)
+ """
+ An array of extra items, includes discounts, shipping, and taxes.
+ """
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ total: typing.Optional[OrderPrice] = pydantic.Field(default=None)
+ """
+ The total price
+ """
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/order_totals_extras_item.py b/src/webflow/types/order_totals_extras_item.py
index e2a70e0..55f9f65 100644
--- a/src/webflow/types/order_totals_extras_item.py
+++ b/src/webflow/types/order_totals_extras_item.py
@@ -1,43 +1,43 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from .order_price import OrderPrice
from .order_totals_extras_item_type import OrderTotalsExtrasItemType
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class OrderTotalsExtrasItem(pydantic.BaseModel):
+class OrderTotalsExtrasItem(UniversalBaseModel):
"""
Extra order items, includes discounts, shipping, and taxes.
"""
- type: typing.Optional[OrderTotalsExtrasItemType] = pydantic.Field(
- default=None, description="The type of extra item this is."
- )
- name: typing.Optional[str] = pydantic.Field(
- default=None, description="A human-readable (but English) name for this extra charge."
- )
- description: typing.Optional[str] = pydantic.Field(
- default=None, description="A human-readable (but English) description of this extra charge."
- )
- price: typing.Optional[OrderPrice] = pydantic.Field(default=None, description="The price for the item")
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- json_encoders = {dt.datetime: serialize_datetime}
+ type: typing.Optional[OrderTotalsExtrasItemType] = pydantic.Field(default=None)
+ """
+ The type of extra item this is.
+ """
+
+ name: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ A human-readable (but English) name for this extra charge.
+ """
+
+ description: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ A human-readable (but English) description of this extra charge.
+ """
+
+ price: typing.Optional[OrderPrice] = pydantic.Field(default=None)
+ """
+ The price for the item
+ """
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/order_totals_extras_item_type.py b/src/webflow/types/order_totals_extras_item_type.py
index 2ec3f09..34a8cb3 100644
--- a/src/webflow/types/order_totals_extras_item_type.py
+++ b/src/webflow/types/order_totals_extras_item_type.py
@@ -1,33 +1,5 @@
# This file was auto-generated by Fern from our API Definition.
-import enum
import typing
-T_Result = typing.TypeVar("T_Result")
-
-
-class OrderTotalsExtrasItemType(str, enum.Enum):
- """
- The type of extra item this is.
- """
-
- DISCOUNT = "discount"
- DISCOUNT_SHIPPING = "discount-shipping"
- SHIPPING = "shipping"
- TAX = "tax"
-
- def visit(
- self,
- discount: typing.Callable[[], T_Result],
- discount_shipping: typing.Callable[[], T_Result],
- shipping: typing.Callable[[], T_Result],
- tax: typing.Callable[[], T_Result],
- ) -> T_Result:
- if self is OrderTotalsExtrasItemType.DISCOUNT:
- return discount()
- if self is OrderTotalsExtrasItemType.DISCOUNT_SHIPPING:
- return discount_shipping()
- if self is OrderTotalsExtrasItemType.SHIPPING:
- return shipping()
- if self is OrderTotalsExtrasItemType.TAX:
- return tax()
+OrderTotalsExtrasItemType = typing.Union[typing.Literal["discount", "discount-shipping", "shipping", "tax"], typing.Any]
diff --git a/src/webflow/types/page.py b/src/webflow/types/page.py
index f67e4b2..f191daa 100644
--- a/src/webflow/types/page.py
+++ b/src/webflow/types/page.py
@@ -3,68 +3,121 @@
import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .page_open_graph import PageOpenGraph
from .page_seo import PageSeo
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class Page(pydantic.BaseModel):
+class Page(UniversalBaseModel):
"""
The Page object
"""
- id: typing.Optional[str] = pydantic.Field(default=None, description="Unique identifier for the Page")
- site_id: typing.Optional[str] = pydantic.Field(
- alias="siteId", default=None, description="Unique identifier for the Site"
- )
- title: typing.Optional[str] = pydantic.Field(default=None, description="Title of the Page")
- slug: typing.Optional[str] = pydantic.Field(default=None, description="slug of the Page (derived from title)")
- parent_id: typing.Optional[str] = pydantic.Field(
- alias="parentId", default=None, description="Identifier of the parent folder"
- )
- collection_id: typing.Optional[str] = pydantic.Field(
- alias="collectionId",
- default=None,
- description="Unique identifier for a linked Collection, value will be null if the Page is not part of a Collection.",
- )
- created_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="createdOn", default=None, description="The date the Page was created"
- )
- last_updated: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastUpdated", default=None, description="The date the Page was most recently updated"
- )
- archived: typing.Optional[bool] = pydantic.Field(default=None, description="Whether the Page has been archived")
- draft: typing.Optional[bool] = pydantic.Field(default=None, description="Whether the Page is a draft")
- can_branch: typing.Optional[bool] = pydantic.Field(
- alias="canBranch",
- default=None,
- description="Indicates whether the Page supports [Page Branching](https://university.webflow.com/lesson/page-branching)",
- )
- is_members_only: typing.Optional[bool] = pydantic.Field(
- alias="isMembersOnly",
- default=None,
- description="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, description="SEO-related fields for the Page")
- open_graph: typing.Optional[PageOpenGraph] = pydantic.Field(
- alias="openGraph", default=None, description="Open Graph fields for the Page"
- )
+ id: str = pydantic.Field()
+ """
+ Unique identifier for the Page
+ """
+
+ site_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="siteId"),
+ pydantic.Field(alias="siteId", description="Unique identifier for the Site"),
+ ] = None
+ title: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Title of the Page
+ """
+
+ slug: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ slug of the Page (derived from title)
+ """
+
+ parent_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="parentId"),
+ pydantic.Field(alias="parentId", description="Identifier of the parent folder"),
+ ] = None
+ collection_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="collectionId"),
+ pydantic.Field(
+ alias="collectionId",
+ description="Unique identifier for a linked Collection, value will be null if the Page is not part of a Collection.",
+ ),
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="The date the Page was created"),
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="The date the Page was most recently updated"),
+ ] = None
+ archived: typing.Optional[bool] = pydantic.Field(default=None)
+ """
+ Whether the Page has been archived
+ """
+
+ draft: typing.Optional[bool] = pydantic.Field(default=None)
+ """
+ Whether the Page is a draft
+ """
+
+ can_branch: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="canBranch"),
+ pydantic.Field(
+ alias="canBranch",
+ description="Indicates whether the Page supports [Page Branching](https://university.webflow.com/lesson/page-branching). Pages that are already branches cannot be branched again.",
+ ),
+ ] = None
+ is_branch: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="isBranch"),
+ pydantic.Field(
+ alias="isBranch",
+ description="Indicates whether the Page is a Branch of another Page [Page Branching](https://university.webflow.com/lesson/page-branching)",
+ ),
+ ] = None
+ branch_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="branchId"),
+ pydantic.Field(
+ alias="branchId", description="If the Page is a Branch of another Page, this is the ID of the Branch"
+ ),
+ ] = None
+ seo: typing.Optional[PageSeo] = pydantic.Field(default=None)
+ """
+ SEO-related fields for the Page
+ """
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ open_graph: typing_extensions.Annotated[
+ typing.Optional[PageOpenGraph],
+ FieldMetadata(alias="openGraph"),
+ pydantic.Field(alias="openGraph", description="Open Graph fields for the Page"),
+ ] = None
+ locale_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="localeId"),
+ pydantic.Field(alias="localeId", description="Unique ID of the page locale"),
+ ] = None
+ published_path: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="publishedPath"),
+ pydantic.Field(alias="publishedPath", description="Relative path of the published page URL"),
+ ] = None
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/page_created_webhook.py b/src/webflow/types/page_created_webhook.py
new file mode 100644
index 0000000..14efaf3
--- /dev/null
+++ b/src/webflow/types/page_created_webhook.py
@@ -0,0 +1,34 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .page_created_webhook_payload import PageCreatedWebhookPayload
+
+
+class PageCreatedWebhook(UniversalBaseModel):
+ """
+ The Webhook payload for when a Page is created
+ """
+
+ trigger_type: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="triggerType"),
+ pydantic.Field(alias="triggerType", description="The type of event that triggered the request"),
+ ] = None
+ payload: typing.Optional[PageCreatedWebhookPayload] = pydantic.Field(default=None)
+ """
+ The payload of data sent from Webflow
+ """
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/page_created_webhook_payload.py b/src/webflow/types/page_created_webhook_payload.py
new file mode 100644
index 0000000..4dd3385
--- /dev/null
+++ b/src/webflow/types/page_created_webhook_payload.py
@@ -0,0 +1,40 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class PageCreatedWebhookPayload(UniversalBaseModel):
+ """
+ The payload of data sent from Webflow
+ """
+
+ site_id: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="siteId"), pydantic.Field(alias="siteId")
+ ] = None
+ page_id: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="pageId"), pydantic.Field(alias="pageId")
+ ] = None
+ page_title: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="pageTitle"), pydantic.Field(alias="pageTitle")
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime], FieldMetadata(alias="createdOn"), pydantic.Field(alias="createdOn")
+ ] = None
+ published_path: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="publishedPath"), pydantic.Field(alias="publishedPath")
+ ] = 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/page_deleted_webhook.py b/src/webflow/types/page_deleted_webhook.py
new file mode 100644
index 0000000..247f4ae
--- /dev/null
+++ b/src/webflow/types/page_deleted_webhook.py
@@ -0,0 +1,34 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .page_deleted_webhook_payload import PageDeletedWebhookPayload
+
+
+class PageDeletedWebhook(UniversalBaseModel):
+ """
+ The Webhook payload for when a Page is deleted
+ """
+
+ trigger_type: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="triggerType"),
+ pydantic.Field(alias="triggerType", description="The type of event that triggered the request"),
+ ] = None
+ payload: typing.Optional[PageDeletedWebhookPayload] = pydantic.Field(default=None)
+ """
+ The payload of data sent from Webflow
+ """
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/page_deleted_webhook_payload.py b/src/webflow/types/page_deleted_webhook_payload.py
new file mode 100644
index 0000000..e78f589
--- /dev/null
+++ b/src/webflow/types/page_deleted_webhook_payload.py
@@ -0,0 +1,40 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class PageDeletedWebhookPayload(UniversalBaseModel):
+ """
+ The payload of data sent from Webflow
+ """
+
+ site_id: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="siteId"), pydantic.Field(alias="siteId")
+ ] = None
+ page_id: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="pageId"), pydantic.Field(alias="pageId")
+ ] = None
+ page_title: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="pageTitle"), pydantic.Field(alias="pageTitle")
+ ] = None
+ deleted_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime], FieldMetadata(alias="deletedOn"), pydantic.Field(alias="deletedOn")
+ ] = None
+ published_path: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="publishedPath"), pydantic.Field(alias="publishedPath")
+ ] = 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/page_list.py b/src/webflow/types/page_list.py
index 3ba1a63..a392bea 100644
--- a/src/webflow/types/page_list.py
+++ b/src/webflow/types/page_list.py
@@ -1,19 +1,14 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from .page import Page
from .pagination import Pagination
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class PageList(pydantic.BaseModel):
+class PageList(UniversalBaseModel):
"""
The Page object
"""
@@ -21,15 +16,11 @@ class PageList(pydantic.BaseModel):
pages: typing.Optional[typing.List[Page]] = None
pagination: typing.Optional[Pagination] = None
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/page_metadata_updated_webhook.py b/src/webflow/types/page_metadata_updated_webhook.py
new file mode 100644
index 0000000..0751f3a
--- /dev/null
+++ b/src/webflow/types/page_metadata_updated_webhook.py
@@ -0,0 +1,34 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .page_metadata_updated_webhook_payload import PageMetadataUpdatedWebhookPayload
+
+
+class PageMetadataUpdatedWebhook(UniversalBaseModel):
+ """
+ The Webhook payload for when a Page's metadata is updated
+ """
+
+ trigger_type: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="triggerType"),
+ pydantic.Field(alias="triggerType", description="The type of event that triggered the request"),
+ ] = None
+ payload: typing.Optional[PageMetadataUpdatedWebhookPayload] = pydantic.Field(default=None)
+ """
+ The payload of data sent from Webflow
+ """
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/page_metadata_updated_webhook_payload.py b/src/webflow/types/page_metadata_updated_webhook_payload.py
new file mode 100644
index 0000000..d71cf47
--- /dev/null
+++ b/src/webflow/types/page_metadata_updated_webhook_payload.py
@@ -0,0 +1,40 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class PageMetadataUpdatedWebhookPayload(UniversalBaseModel):
+ """
+ The payload of data sent from Webflow
+ """
+
+ site_id: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="siteId"), pydantic.Field(alias="siteId")
+ ] = None
+ page_id: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="pageId"), pydantic.Field(alias="pageId")
+ ] = None
+ page_title: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="pageTitle"), pydantic.Field(alias="pageTitle")
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[dt.datetime], FieldMetadata(alias="lastUpdated"), pydantic.Field(alias="lastUpdated")
+ ] = None
+ published_path: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="publishedPath"), pydantic.Field(alias="publishedPath")
+ ] = 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/page_open_graph.py b/src/webflow/types/page_open_graph.py
index 2c7f5fb..63d6898 100644
--- a/src/webflow/types/page_open_graph.py
+++ b/src/webflow/types/page_open_graph.py
@@ -1,46 +1,47 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class PageOpenGraph(pydantic.BaseModel):
+class PageOpenGraph(UniversalBaseModel):
"""
Open Graph fields for the Page
"""
- title: typing.Optional[str] = pydantic.Field(
- default=None, description="The title supplied to Open Graph annotations"
- )
- title_copied: typing.Optional[bool] = pydantic.Field(
- alias="titleCopied", default=None, description="Indicates the Open Graph title was copied from the SEO title"
- )
- description: typing.Optional[str] = pydantic.Field(
- default=None, description="The description supplied to Open Graph annotations"
- )
- description_copied: typing.Optional[bool] = pydantic.Field(
- alias="descriptionCopied",
- default=None,
- description="Indicates the Open Graph description was copied from the SEO description",
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ title: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The title supplied to Open Graph annotations
+ """
+
+ title_copied: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="titleCopied"),
+ pydantic.Field(alias="titleCopied", description="Indicates the Open Graph title was copied from the SEO title"),
+ ] = None
+ description: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The description supplied to Open Graph annotations
+ """
+
+ description_copied: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="descriptionCopied"),
+ pydantic.Field(
+ alias="descriptionCopied",
+ description="Indicates the Open Graph description was copied from the SEO description",
+ ),
+ ] = 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/page_seo.py b/src/webflow/types/page_seo.py
index 091d1e9..4182b16 100644
--- a/src/webflow/types/page_seo.py
+++ b/src/webflow/types/page_seo.py
@@ -1,37 +1,31 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class PageSeo(pydantic.BaseModel):
+class PageSeo(UniversalBaseModel):
"""
SEO-related fields for the Page
"""
- title: typing.Optional[str] = pydantic.Field(
- default=None, description="The Page title shown in search engine results"
- )
- description: typing.Optional[str] = pydantic.Field(
- default=None, description="The Page description shown in search engine results"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- json_encoders = {dt.datetime: serialize_datetime}
+ title: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The Page title shown in search engine results
+ """
+
+ description: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The Page description shown in search engine results
+ """
+
+ 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/pagination.py b/src/webflow/types/pagination.py
index b8bb3b6..72cd209 100644
--- a/src/webflow/types/pagination.py
+++ b/src/webflow/types/pagination.py
@@ -1,34 +1,36 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class Pagination(pydantic.BaseModel):
+class Pagination(UniversalBaseModel):
"""
Pagination object
"""
- limit: typing.Optional[float] = pydantic.Field(default=None, description="The limit used for pagination")
- offset: typing.Optional[float] = pydantic.Field(default=None, description="The offset used for pagination")
- total: typing.Optional[float] = pydantic.Field(default=None, description="The total number of records")
+ limit: typing.Optional[int] = pydantic.Field(default=None)
+ """
+ The limit used for pagination
+ """
+
+ offset: typing.Optional[int] = pydantic.Field(default=None)
+ """
+ The offset used for pagination
+ """
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ total: typing.Optional[int] = pydantic.Field(default=None)
+ """
+ The total number of records
+ """
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/payload.py b/src/webflow/types/payload.py
new file mode 100644
index 0000000..efd0d48
--- /dev/null
+++ b/src/webflow/types/payload.py
@@ -0,0 +1,69 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .payload_field_data import PayloadFieldData
+
+
+class Payload(UniversalBaseModel):
+ """
+ The payload of data sent from Webflow
+ """
+
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The ID of the collection item that was unpublished
+ """
+
+ site_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="siteId"),
+ pydantic.Field(alias="siteId", description="The ID of the site"),
+ ] = None
+ workspace_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="workspaceId"),
+ pydantic.Field(alias="workspaceId", description="The ID of the workspace"),
+ ] = None
+ collection_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="collectionId"),
+ pydantic.Field(alias="collectionId", description="The ID of the collection"),
+ ] = None
+ cms_locale_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="cmsLocaleId"),
+ pydantic.Field(alias="cmsLocaleId", description="Unique identifier of the CMS locale for this item"),
+ ] = None
+ last_published: typing_extensions.Annotated[
+ typing.Optional[dt.datetime], FieldMetadata(alias="lastPublished"), pydantic.Field(alias="lastPublished")
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[dt.datetime], FieldMetadata(alias="lastUpdated"), pydantic.Field(alias="lastUpdated")
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime], FieldMetadata(alias="createdOn"), pydantic.Field(alias="createdOn")
+ ] = None
+ is_archived: typing_extensions.Annotated[
+ typing.Optional[bool], FieldMetadata(alias="isArchived"), pydantic.Field(alias="isArchived")
+ ] = None
+ is_draft: typing_extensions.Annotated[
+ typing.Optional[bool], FieldMetadata(alias="isDraft"), pydantic.Field(alias="isDraft")
+ ] = None
+ field_data: typing_extensions.Annotated[
+ typing.Optional[PayloadFieldData], FieldMetadata(alias="fieldData"), pydantic.Field(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/types/payload_field_data.py b/src/webflow/types/payload_field_data.py
new file mode 100644
index 0000000..c8c69ce
--- /dev/null
+++ b/src/webflow/types/payload_field_data.py
@@ -0,0 +1,20 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class PayloadFieldData(UniversalBaseModel):
+ name: str
+ slug: str
+
+ 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/paypal_details.py b/src/webflow/types/paypal_details.py
index 80afce3..9ed4a6e 100644
--- a/src/webflow/types/paypal_details.py
+++ b/src/webflow/types/paypal_details.py
@@ -1,46 +1,50 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class PaypalDetails(pydantic.BaseModel):
- order_id: typing.Optional[str] = pydantic.Field(
- alias="orderId", default=None, description="PayPal order identifier"
- )
- payer_id: typing.Optional[str] = pydantic.Field(
- alias="payerId", default=None, description="PayPal payer identifier"
- )
- capture_id: typing.Optional[str] = pydantic.Field(
- alias="captureId", default=None, description="PayPal capture identifier"
- )
- refund_id: typing.Optional[str] = pydantic.Field(
- alias="refundId", default=None, description="PayPal refund identifier"
- )
- refund_reason: typing.Optional[str] = pydantic.Field(
- alias="refundReason", default=None, description="PayPal-issued reason for the refund"
- )
- dispute_id: typing.Optional[str] = pydantic.Field(
- alias="disputeId", default=None, description="PayPal dispute identifier"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class PaypalDetails(UniversalBaseModel):
+ order_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="orderId"),
+ pydantic.Field(alias="orderId", description="PayPal order identifier"),
+ ] = None
+ payer_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="payerId"),
+ pydantic.Field(alias="payerId", description="PayPal payer identifier"),
+ ] = None
+ capture_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="captureId"),
+ pydantic.Field(alias="captureId", description="PayPal capture identifier"),
+ ] = None
+ refund_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="refundId"),
+ pydantic.Field(alias="refundId", description="PayPal refund identifier"),
+ ] = None
+ refund_reason: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="refundReason"),
+ pydantic.Field(alias="refundReason", description="PayPal-issued reason for the refund"),
+ ] = None
+ dispute_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="disputeId"),
+ pydantic.Field(alias="disputeId", description="PayPal dispute identifier"),
+ ] = 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/product.py b/src/webflow/types/product.py
index 81e7372..f0e48bd 100644
--- a/src/webflow/types/product.py
+++ b/src/webflow/types/product.py
@@ -3,48 +3,62 @@
import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .product_field_data import ProductFieldData
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class Product(pydantic.BaseModel):
+class Product(UniversalBaseModel):
"""
The Product object
"""
- id: typing.Optional[str] = pydantic.Field(default=None, description="Unique identifier for the Product")
- last_published: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastPublished", default=None, description="The date the Product was last published"
- )
- last_updated: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastUpdated", default=None, description="The date the Product was last updated"
- )
- created_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="createdOn", default=None, description="The date the Product was created"
- )
- is_archived: typing.Optional[bool] = pydantic.Field(
- alias="isArchived", default=None, description="Boolean determining if the Product is set to archived"
- )
- is_draft: typing.Optional[bool] = pydantic.Field(
- alias="isDraft", default=None, description="Boolean determining if the Product is set to draft"
- )
- field_data: typing.Optional[ProductFieldData] = pydantic.Field(alias="fieldData", default=None)
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Unique identifier for the Product
+ """
+
+ cms_locale_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="cmsLocaleId"),
+ pydantic.Field(alias="cmsLocaleId", description="Identifier for the locale of the CMS item"),
+ ] = None
+ last_published: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="lastPublished"),
+ pydantic.Field(alias="lastPublished", description="The date the Product was last published"),
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="The date the Product was last updated"),
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="The date the Product was created"),
+ ] = None
+ is_archived: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="isArchived"),
+ pydantic.Field(alias="isArchived", description="Boolean determining if the Product is set to archived"),
+ ] = None
+ is_draft: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="isDraft"),
+ pydantic.Field(alias="isDraft", description="Boolean determining if the Product is set to draft"),
+ ] = None
+ field_data: typing_extensions.Annotated[
+ typing.Optional[ProductFieldData], FieldMetadata(alias="fieldData"), pydantic.Field(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/types/product_and_sk_us.py b/src/webflow/types/product_and_sk_us.py
index 64ee6b5..42b5b62 100644
--- a/src/webflow/types/product_and_sk_us.py
+++ b/src/webflow/types/product_and_sk_us.py
@@ -1,35 +1,29 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from .product import Product
from .sku import Sku
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class ProductAndSkUs(pydantic.BaseModel):
+class ProductAndSkUs(UniversalBaseModel):
"""
A product and its SKUs.
"""
product: typing.Optional[Product] = None
- skus: typing.Optional[typing.List[Sku]] = pydantic.Field(default=None, description="A list of SKU Objects")
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ skus: typing.Optional[typing.List[Sku]] = pydantic.Field(default=None)
+ """
+ A list of SKU Objects
+ """
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/product_and_sk_us_list.py b/src/webflow/types/product_and_sk_us_list.py
index 0c2eae5..a2060d7 100644
--- a/src/webflow/types/product_and_sk_us_list.py
+++ b/src/webflow/types/product_and_sk_us_list.py
@@ -1,38 +1,30 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from .pagination import Pagination
from .product_and_sk_us import ProductAndSkUs
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class ProductAndSkUsList(pydantic.BaseModel):
+class ProductAndSkUsList(UniversalBaseModel):
"""
Results from product list
"""
- items: typing.Optional[typing.List[ProductAndSkUs]] = pydantic.Field(
- default=None,
- description="List of Item objects within the Collection. Contains product and skus keys for each Item",
- )
- pagination: typing.Optional[Pagination] = None
+ items: typing.Optional[typing.List[ProductAndSkUs]] = pydantic.Field(default=None)
+ """
+ List of Item objects within the Collection. Contains product and skus keys for each Item
+ """
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ pagination: typing.Optional[Pagination] = None
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/product_field_data.py b/src/webflow/types/product_field_data.py
index 756c629..b9c15fb 100644
--- a/src/webflow/types/product_field_data.py
+++ b/src/webflow/types/product_field_data.py
@@ -1,57 +1,75 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .product_field_data_ec_product_type import ProductFieldDataEcProductType
from .product_field_data_tax_category import ProductFieldDataTaxCategory
from .sku_property_list import SkuPropertyList
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class ProductFieldData(pydantic.BaseModel):
- name: str = pydantic.Field(description="Name of the Product")
- slug: str = pydantic.Field(description="URL structure of the Product in your site.")
- description: typing.Optional[str] = pydantic.Field(default=None, description="A description of your product")
- shippable: typing.Optional[bool] = pydantic.Field(
- default=None, description="Boolean determining if the Product is shippable"
- )
- sku_properties: typing.Optional[typing.List[SkuPropertyList]] = pydantic.Field(
- alias="sku-properties", default=None, description="Variant types to include in SKUs"
- )
- categories: typing.Optional[typing.List[str]] = pydantic.Field(
- default=None, description="The categories your product belongs to."
- )
- tax_category: typing.Optional[ProductFieldDataTaxCategory] = pydantic.Field(
- alias="tax-category", default=None, description="Product tax class"
- )
- default_sku: typing.Optional[str] = pydantic.Field(
- alias="default-sku", default=None, description="The default SKU associated with this product."
- )
- ec_product_type: typing.Optional[ProductFieldDataEcProductType] = pydantic.Field(
- alias="ec-product-type",
- default=None,
- description='Product types. Enums reflect the following values in order: Physical, Digital, Service, Advanced"',
- )
- additional_properties: typing.Optional[str] = pydantic.Field(
- alias="additionalProperties", default=None, description="Custom fields for your product."
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+
+class ProductFieldData(UniversalBaseModel):
+ """
+ Contains content-specific details for a product, covering both standard (e.g., title, description) and custom fields tailored to the product setup.
+ """
+
+ name: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Name of the Product
+ """
+
+ slug: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ URL structure of the Product in your site.
+ """
+
+ description: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ A description of your product
+ """
+
+ shippable: typing.Optional[bool] = pydantic.Field(default=None)
+ """
+ Boolean determining if the Product is shippable
+ """
+
+ sku_properties: typing_extensions.Annotated[
+ typing.Optional[typing.List[SkuPropertyList]],
+ FieldMetadata(alias="sku-properties"),
+ pydantic.Field(alias="sku-properties", description="Variant types to include in SKUs"),
+ ] = None
+ category: typing.Optional[typing.List[str]] = pydantic.Field(default=None)
+ """
+ The category your product belongs to.
+ """
+
+ tax_category: typing_extensions.Annotated[
+ typing.Optional[ProductFieldDataTaxCategory],
+ FieldMetadata(alias="tax-category"),
+ pydantic.Field(alias="tax-category", description="Product tax class"),
+ ] = None
+ default_sku: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="default-sku"),
+ pydantic.Field(alias="default-sku", description="The default SKU associated with this product."),
+ ] = None
+ ec_product_type: typing_extensions.Annotated[
+ typing.Optional[ProductFieldDataEcProductType],
+ FieldMetadata(alias="ec-product-type"),
+ pydantic.Field(
+ alias="ec-product-type",
+ description='Product types. Enums reflect the following values in order: Physical, Digital, Service, Advanced"',
+ ),
+ ] = 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/product_field_data_ec_product_type.py b/src/webflow/types/product_field_data_ec_product_type.py
index f496e5a..8a74a70 100644
--- a/src/webflow/types/product_field_data_ec_product_type.py
+++ b/src/webflow/types/product_field_data_ec_product_type.py
@@ -1,33 +1,13 @@
# This file was auto-generated by Fern from our API Definition.
-import enum
import typing
-T_Result = typing.TypeVar("T_Result")
-
-
-class ProductFieldDataEcProductType(str, enum.Enum):
- """
- Product types. Enums reflect the following values in order: Physical, Digital, Service, Advanced"
- """
-
- FF_42_FEE_0113744_F_693_A_764_E_3431_A_9_CC_2 = "ff42fee0113744f693a764e3431a9cc2"
- F_22027_DB_68002190_AEF_89_A_4_A_2_B_7_AC_8_A_1 = "f22027db68002190aef89a4a2b7ac8a1"
- C_599_E_43_B_1_A_1_C_34_D_5_A_323_AEDF_75_D_3_ADF_6 = "c599e43b1a1c34d5a323aedf75d3adf6"
- B_6_CCC_1830_DB_4_B_1_BABEB_06_A_9_AC_5_F_6_DD_76 = "b6ccc1830db4b1babeb06a9ac5f6dd76"
-
- def visit(
- self,
- ff_42_fee_0113744_f_693_a_764_e_3431_a_9_cc_2: typing.Callable[[], T_Result],
- f_22027_db_68002190_aef_89_a_4_a_2_b_7_ac_8_a_1: typing.Callable[[], T_Result],
- c_599_e_43_b_1_a_1_c_34_d_5_a_323_aedf_75_d_3_adf_6: typing.Callable[[], T_Result],
- b_6_ccc_1830_db_4_b_1_babeb_06_a_9_ac_5_f_6_dd_76: typing.Callable[[], T_Result],
- ) -> T_Result:
- if self is ProductFieldDataEcProductType.FF_42_FEE_0113744_F_693_A_764_E_3431_A_9_CC_2:
- return ff_42_fee_0113744_f_693_a_764_e_3431_a_9_cc_2()
- if self is ProductFieldDataEcProductType.F_22027_DB_68002190_AEF_89_A_4_A_2_B_7_AC_8_A_1:
- return f_22027_db_68002190_aef_89_a_4_a_2_b_7_ac_8_a_1()
- if self is ProductFieldDataEcProductType.C_599_E_43_B_1_A_1_C_34_D_5_A_323_AEDF_75_D_3_ADF_6:
- return c_599_e_43_b_1_a_1_c_34_d_5_a_323_aedf_75_d_3_adf_6()
- if self is ProductFieldDataEcProductType.B_6_CCC_1830_DB_4_B_1_BABEB_06_A_9_AC_5_F_6_DD_76:
- return b_6_ccc_1830_db_4_b_1_babeb_06_a_9_ac_5_f_6_dd_76()
+ProductFieldDataEcProductType = typing.Union[
+ typing.Literal[
+ "ff42fee0113744f693a764e3431a9cc2",
+ "f22027db68002190aef89a4a2b7ac8a1",
+ "c599e43b1a1c34d5a323aedf75d3adf6",
+ "b6ccc1830db4b1babeb06a9ac5f6dd76",
+ ],
+ typing.Any,
+]
diff --git a/src/webflow/types/product_field_data_tax_category.py b/src/webflow/types/product_field_data_tax_category.py
index bb27b51..54de073 100644
--- a/src/webflow/types/product_field_data_tax_category.py
+++ b/src/webflow/types/product_field_data_tax_category.py
@@ -1,133 +1,38 @@
# This file was auto-generated by Fern from our API Definition.
-import enum
import typing
-T_Result = typing.TypeVar("T_Result")
-
-
-class ProductFieldDataTaxCategory(str, enum.Enum):
- """
- Product tax class
- """
-
- STANDARD_TAXABLE = "standard-taxable"
- STANDARD_EXEMPT = "standard-exempt"
- BOOKS_RELIGIOUS = "books-religious"
- BOOKS_TEXTBOOK = "books-textbook"
- CLOTHING = "clothing"
- CLOTHING_SWIMWEAR = "clothing-swimwear"
- DIGITAL_GOODS = "digital-goods"
- DIGITAL_SERVICE = "digital-service"
- DRUGS_NON_PRESCRIPTION = "drugs-non-prescription"
- DRUGS_PRESCRIPTION = "drugs-prescription"
- FOOD_BOTTLED_WATER = "food-bottled-water"
- FOOD_CANDY = "food-candy"
- FOOD_GROCERIES = "food-groceries"
- FOOD_PREPARED = "food-prepared"
- FOOD_SODA = "food-soda"
- FOOD_SUPPLEMENTS = "food-supplements"
- MAGAZINE_INDIVIDUAL = "magazine-individual"
- MAGAZINE_SUBSCRIPTION = "magazine-subscription"
- SERVICE_ADMISSION = "service-admission"
- SERVICE_ADVERTISING = "service-advertising"
- SERVICE_DRY_CLEANING = "service-dry-cleaning"
- SERVICE_HAIRDRESSING = "service-hairdressing"
- SERVICE_INSTALLATION = "service-installation"
- SERVICE_MISCELLANEOUS = "service-miscellaneous"
- SERVICE_PARKING = "service-parking"
- SERVICE_PRINTING = "service-printing"
- SERVICE_PROFESSIONAL = "service-professional"
- SERVICE_REPAIR = "service-repair"
- SERVICE_TRAINING = "service-training"
-
- def visit(
- self,
- standard_taxable: typing.Callable[[], T_Result],
- standard_exempt: typing.Callable[[], T_Result],
- books_religious: typing.Callable[[], T_Result],
- books_textbook: typing.Callable[[], T_Result],
- clothing: typing.Callable[[], T_Result],
- clothing_swimwear: typing.Callable[[], T_Result],
- digital_goods: typing.Callable[[], T_Result],
- digital_service: typing.Callable[[], T_Result],
- drugs_non_prescription: typing.Callable[[], T_Result],
- drugs_prescription: typing.Callable[[], T_Result],
- food_bottled_water: typing.Callable[[], T_Result],
- food_candy: typing.Callable[[], T_Result],
- food_groceries: typing.Callable[[], T_Result],
- food_prepared: typing.Callable[[], T_Result],
- food_soda: typing.Callable[[], T_Result],
- food_supplements: typing.Callable[[], T_Result],
- magazine_individual: typing.Callable[[], T_Result],
- magazine_subscription: typing.Callable[[], T_Result],
- service_admission: typing.Callable[[], T_Result],
- service_advertising: typing.Callable[[], T_Result],
- service_dry_cleaning: typing.Callable[[], T_Result],
- service_hairdressing: typing.Callable[[], T_Result],
- service_installation: typing.Callable[[], T_Result],
- service_miscellaneous: typing.Callable[[], T_Result],
- service_parking: typing.Callable[[], T_Result],
- service_printing: typing.Callable[[], T_Result],
- service_professional: typing.Callable[[], T_Result],
- service_repair: typing.Callable[[], T_Result],
- service_training: typing.Callable[[], T_Result],
- ) -> T_Result:
- if self is ProductFieldDataTaxCategory.STANDARD_TAXABLE:
- return standard_taxable()
- if self is ProductFieldDataTaxCategory.STANDARD_EXEMPT:
- return standard_exempt()
- if self is ProductFieldDataTaxCategory.BOOKS_RELIGIOUS:
- return books_religious()
- if self is ProductFieldDataTaxCategory.BOOKS_TEXTBOOK:
- return books_textbook()
- if self is ProductFieldDataTaxCategory.CLOTHING:
- return clothing()
- if self is ProductFieldDataTaxCategory.CLOTHING_SWIMWEAR:
- return clothing_swimwear()
- if self is ProductFieldDataTaxCategory.DIGITAL_GOODS:
- return digital_goods()
- if self is ProductFieldDataTaxCategory.DIGITAL_SERVICE:
- return digital_service()
- if self is ProductFieldDataTaxCategory.DRUGS_NON_PRESCRIPTION:
- return drugs_non_prescription()
- if self is ProductFieldDataTaxCategory.DRUGS_PRESCRIPTION:
- return drugs_prescription()
- if self is ProductFieldDataTaxCategory.FOOD_BOTTLED_WATER:
- return food_bottled_water()
- if self is ProductFieldDataTaxCategory.FOOD_CANDY:
- return food_candy()
- if self is ProductFieldDataTaxCategory.FOOD_GROCERIES:
- return food_groceries()
- if self is ProductFieldDataTaxCategory.FOOD_PREPARED:
- return food_prepared()
- if self is ProductFieldDataTaxCategory.FOOD_SODA:
- return food_soda()
- if self is ProductFieldDataTaxCategory.FOOD_SUPPLEMENTS:
- return food_supplements()
- if self is ProductFieldDataTaxCategory.MAGAZINE_INDIVIDUAL:
- return magazine_individual()
- if self is ProductFieldDataTaxCategory.MAGAZINE_SUBSCRIPTION:
- return magazine_subscription()
- if self is ProductFieldDataTaxCategory.SERVICE_ADMISSION:
- return service_admission()
- if self is ProductFieldDataTaxCategory.SERVICE_ADVERTISING:
- return service_advertising()
- if self is ProductFieldDataTaxCategory.SERVICE_DRY_CLEANING:
- return service_dry_cleaning()
- if self is ProductFieldDataTaxCategory.SERVICE_HAIRDRESSING:
- return service_hairdressing()
- if self is ProductFieldDataTaxCategory.SERVICE_INSTALLATION:
- return service_installation()
- if self is ProductFieldDataTaxCategory.SERVICE_MISCELLANEOUS:
- return service_miscellaneous()
- if self is ProductFieldDataTaxCategory.SERVICE_PARKING:
- return service_parking()
- if self is ProductFieldDataTaxCategory.SERVICE_PRINTING:
- return service_printing()
- if self is ProductFieldDataTaxCategory.SERVICE_PROFESSIONAL:
- return service_professional()
- if self is ProductFieldDataTaxCategory.SERVICE_REPAIR:
- return service_repair()
- if self is ProductFieldDataTaxCategory.SERVICE_TRAINING:
- return service_training()
+ProductFieldDataTaxCategory = typing.Union[
+ typing.Literal[
+ "standard-taxable",
+ "standard-exempt",
+ "books-religious",
+ "books-textbook",
+ "clothing",
+ "clothing-swimwear",
+ "digital-goods",
+ "digital-service",
+ "drugs-non-prescription",
+ "drugs-prescription",
+ "food-bottled-water",
+ "food-candy",
+ "food-groceries",
+ "food-prepared",
+ "food-soda",
+ "food-supplements",
+ "magazine-individual",
+ "magazine-subscription",
+ "service-admission",
+ "service-advertising",
+ "service-dry-cleaning",
+ "service-hairdressing",
+ "service-installation",
+ "service-miscellaneous",
+ "service-parking",
+ "service-printing",
+ "service-professional",
+ "service-repair",
+ "service-training",
+ ],
+ typing.Any,
+]
diff --git a/src/webflow/types/publish_status.py b/src/webflow/types/publish_status.py
index dbee8d9..127f06a 100644
--- a/src/webflow/types/publish_status.py
+++ b/src/webflow/types/publish_status.py
@@ -1,21 +1,5 @@
# This file was auto-generated by Fern from our API Definition.
-import enum
import typing
-T_Result = typing.TypeVar("T_Result")
-
-
-class PublishStatus(str, enum.Enum):
- """
- Indicate whether your Product should be set as "staging" or "live"
- """
-
- STAGING = "staging"
- LIVE = "live"
-
- def visit(self, staging: typing.Callable[[], T_Result], live: typing.Callable[[], T_Result]) -> T_Result:
- if self is PublishStatus.STAGING:
- return staging()
- if self is PublishStatus.LIVE:
- return live()
+PublishStatus = typing.Union[typing.Literal["staging", "live"], typing.Any]
diff --git a/src/webflow/types/redirect.py b/src/webflow/types/redirect.py
new file mode 100644
index 0000000..4937365
--- /dev/null
+++ b/src/webflow/types/redirect.py
@@ -0,0 +1,39 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class Redirect(UniversalBaseModel):
+ """
+ A single redirection rule, specifying a source URL and a destination URL.
+ """
+
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The ID of the specific redirect rule
+ """
+
+ from_url: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="fromUrl"),
+ pydantic.Field(alias="fromUrl", description="The source URL path that will be redirected."),
+ ] = None
+ to_url: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="toUrl"),
+ pydantic.Field(alias="toUrl", description="The target URL path where the user or client will be redirected."),
+ ] = 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/redirects.py b/src/webflow/types/redirects.py
new file mode 100644
index 0000000..5126ce1
--- /dev/null
+++ b/src/webflow/types/redirects.py
@@ -0,0 +1,30 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .pagination import Pagination
+from .redirect import Redirect
+
+
+class Redirects(UniversalBaseModel):
+ """
+ Site redirects response
+ """
+
+ redirects: typing.Optional[typing.List[Redirect]] = pydantic.Field(default=None)
+ """
+ List of redirects for a given site
+ """
+
+ 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/reference_field.py b/src/webflow/types/reference_field.py
new file mode 100644
index 0000000..fa2efe6
--- /dev/null
+++ b/src/webflow/types/reference_field.py
@@ -0,0 +1,54 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .reference_field_metadata import ReferenceFieldMetadata
+from .reference_field_type import ReferenceFieldType
+
+
+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(alias="isEditable", description="Define whether the field is editable"),
+ ] = None
+ is_required: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="isRequired"),
+ pydantic.Field(alias="isRequired", description="define whether a field is required in a collection"),
+ ] = None
+ type: ReferenceFieldType = pydantic.Field()
+ """
+ Choose these appropriate field type for your collection data
+ """
+
+ display_name: typing_extensions.Annotated[
+ str, FieldMetadata(alias="displayName"), pydantic.Field(alias="displayName", description="The name of a field")
+ ]
+ help_text: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="helpText"),
+ pydantic.Field(alias="helpText", description="Additional text to help anyone filling out this field"),
+ ] = None
+ 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..0a6bb01
--- /dev/null
+++ b/src/webflow/types/reference_field_metadata.py
@@ -0,0 +1,29 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class 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(alias="collectionId", description="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 96bcbaa..8822e68 100644
--- a/src/webflow/types/registered_script_list.py
+++ b/src/webflow/types/registered_script_list.py
@@ -1,32 +1,32 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
-from .custom_code_response import CustomCodeResponse
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class RegisteredScriptList(pydantic.BaseModel):
- registered_scripts: typing.Optional[typing.List[CustomCodeResponse]] = pydantic.Field(
- alias="registeredScripts", default=None
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .custom_code_hosted_response import CustomCodeHostedResponse
+from .pagination import Pagination
+
+
+class RegisteredScriptList(UniversalBaseModel):
+ """
+ A list of scripts registered to the site
+ """
+
+ registered_scripts: typing_extensions.Annotated[
+ typing.Optional[typing.List[CustomCodeHostedResponse]],
+ FieldMetadata(alias="registeredScripts"),
+ pydantic.Field(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
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/robots.py b/src/webflow/types/robots.py
new file mode 100644
index 0000000..6a6170e
--- /dev/null
+++ b/src/webflow/types/robots.py
@@ -0,0 +1,32 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .robots_rules_item import RobotsRulesItem
+
+
+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..27c8a5e
--- /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.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class RobotsRulesItem(UniversalBaseModel):
+ user_agent: typing_extensions.Annotated[
+ str,
+ FieldMetadata(alias="userAgent"),
+ pydantic.Field(alias="userAgent", description="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/script_apply.py b/src/webflow/types/script_apply.py
index 2868113..e2bd746 100644
--- a/src/webflow/types/script_apply.py
+++ b/src/webflow/types/script_apply.py
@@ -1,36 +1,38 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from .script_apply_location import ScriptApplyLocation
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class ScriptApply(pydantic.BaseModel):
- id: str = pydantic.Field(description="Id of the registered custom code script")
- location: ScriptApplyLocation = pydantic.Field(
- description="Location of the script, either in the header or footer of the published site"
- )
- version: str = pydantic.Field(description="Semantic Version String for the registered script _e.g. 0.0.1_")
- attributes: typing.Optional[typing.Dict[str, typing.Any]] = pydantic.Field(
- default=None, description="Developer-specified key/value pairs to be applied as attributes to the script"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- json_encoders = {dt.datetime: serialize_datetime}
+
+class ScriptApply(UniversalBaseModel):
+ id: str = pydantic.Field()
+ """
+ ID of the registered custom code script
+ """
+
+ location: ScriptApplyLocation = pydantic.Field()
+ """
+ Location of the script, either in the header or footer of the published site
+ """
+
+ version: str = pydantic.Field()
+ """
+ Semantic Version String for the registered script *e.g. 0.0.1*
+ """
+
+ attributes: typing.Optional[typing.Dict[str, typing.Any]] = pydantic.Field(default=None)
+ """
+ Developer-specified key/value pairs to be applied as attributes to the script
+ """
+
+ 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/script_apply_list.py b/src/webflow/types/script_apply_list.py
index 23e7579..89c79f4 100644
--- a/src/webflow/types/script_apply_list.py
+++ b/src/webflow/types/script_apply_list.py
@@ -1,36 +1,36 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .script_apply import ScriptApply
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class ScriptApplyList(pydantic.BaseModel):
- scripts: typing.Optional[typing.List[ScriptApply]] = None
- last_updated: typing.Optional[str] = pydantic.Field(
- alias="lastUpdated", default=None, description="Date when the Site's scripts were last updated"
- )
- created_on: typing.Optional[str] = pydantic.Field(
- alias="createdOn", default=None, description="Date when the Site's scripts were created"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+class ScriptApplyList(UniversalBaseModel):
+ scripts: typing.Optional[typing.List[ScriptApply]] = pydantic.Field(default=None)
+ """
+ A list of scripts applied to a Site or a Page
+ """
+
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="Date when the Site's scripts were last updated"),
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="Date when the Site's scripts were created"),
+ ] = 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/script_apply_location.py b/src/webflow/types/script_apply_location.py
index e5435c8..6ee3b0a 100644
--- a/src/webflow/types/script_apply_location.py
+++ b/src/webflow/types/script_apply_location.py
@@ -1,21 +1,5 @@
# This file was auto-generated by Fern from our API Definition.
-import enum
import typing
-T_Result = typing.TypeVar("T_Result")
-
-
-class ScriptApplyLocation(str, enum.Enum):
- """
- Location of the script, either in the header or footer of the published site
- """
-
- HEADER = "header"
- FOOTER = "footer"
-
- def visit(self, header: typing.Callable[[], T_Result], footer: typing.Callable[[], T_Result]) -> T_Result:
- if self is ScriptApplyLocation.HEADER:
- return header()
- if self is ScriptApplyLocation.FOOTER:
- return footer()
+ScriptApplyLocation = typing.Union[typing.Literal["header", "footer"], typing.Any]
diff --git a/src/webflow/types/search_button_node.py b/src/webflow/types/search_button_node.py
new file mode 100644
index 0000000..7e40c75
--- /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.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+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: str = pydantic.Field()
+ """
+ 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/search_button_node_write.py b/src/webflow/types/search_button_node_write.py
new file mode 100644
index 0000000..532f4b3
--- /dev/null
+++ b/src/webflow/types/search_button_node_write.py
@@ -0,0 +1,31 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class SearchButtonNodeWrite(UniversalBaseModel):
+ """
+ Update a search button node
+ """
+
+ node_id: typing_extensions.Annotated[
+ str, FieldMetadata(alias="nodeId"), pydantic.Field(alias="nodeId", description="Node UUID")
+ ]
+ value: str = pydantic.Field()
+ """
+ The text content of the search button.
+ """
+
+ 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..d39d5c3
--- /dev/null
+++ b/src/webflow/types/select.py
@@ -0,0 +1,32 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .select_node_write_choices_item import SelectNodeWriteChoicesItem
+
+
+class Select(UniversalBaseModel):
+ """
+ Update choices on a select node
+ """
+
+ node_id: typing_extensions.Annotated[
+ str, FieldMetadata(alias="nodeId"), pydantic.Field(alias="nodeId", description="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..17ca346
--- /dev/null
+++ b/src/webflow/types/select_node.py
@@ -0,0 +1,37 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .select_node_choices_item import SelectNodeChoicesItem
+
+
+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: str = pydantic.Field()
+ """
+ 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..cb0bf0d
--- /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.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+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..05f5108
--- /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.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+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/setting_change.py b/src/webflow/types/setting_change.py
new file mode 100644
index 0000000..c2de45a
--- /dev/null
+++ b/src/webflow/types/setting_change.py
@@ -0,0 +1,27 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .workspace_audit_log_item_payload_setting_change_method import WorkspaceAuditLogItemPayloadSettingChangeMethod
+
+
+class SettingChange(UniversalBaseModel):
+ setting: typing.Optional[typing.Literal["ai_toggle"]] = None
+ previous_value: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="previousValue"), pydantic.Field(alias="previousValue")
+ ] = None
+ value: typing.Optional[str] = None
+ method: typing.Optional[WorkspaceAuditLogItemPayloadSettingChangeMethod] = 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/setting_change_audit_log_item.py b/src/webflow/types/setting_change_audit_log_item.py
new file mode 100644
index 0000000..6846347
--- /dev/null
+++ b/src/webflow/types/setting_change_audit_log_item.py
@@ -0,0 +1,27 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .setting_change import SettingChange
+
+
+class SettingChangeAuditLogItem(UniversalBaseModel):
+ event_sub_type: typing_extensions.Annotated[
+ typing.Optional[typing.Literal["setting_updated"]],
+ FieldMetadata(alias="eventSubType"),
+ pydantic.Field(alias="eventSubType"),
+ ] = None
+ payload: typing.Optional[SettingChange] = 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/single_locale_created_payload.py b/src/webflow/types/single_locale_created_payload.py
new file mode 100644
index 0000000..ea086d2
--- /dev/null
+++ b/src/webflow/types/single_locale_created_payload.py
@@ -0,0 +1,63 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .single_locale_created_payload_field_data import SingleLocaleCreatedPayloadFieldData
+
+
+class SingleLocaleCreatedPayload(UniversalBaseModel):
+ id: str = pydantic.Field()
+ """
+ Unique identifier for the Item
+ """
+
+ workspace_id: typing_extensions.Annotated[
+ str,
+ FieldMetadata(alias="workspaceId"),
+ pydantic.Field(alias="workspaceId", description="Unique identifier of the workspace"),
+ ]
+ site_id: typing_extensions.Annotated[
+ str, FieldMetadata(alias="siteId"), pydantic.Field(alias="siteId", description="Unique identifier of the site")
+ ]
+ collection_id: typing_extensions.Annotated[
+ str,
+ FieldMetadata(alias="collectionId"),
+ pydantic.Field(alias="collectionId", description="Unique identifier of the collection"),
+ ]
+ cms_locale_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="cmsLocaleId"),
+ pydantic.Field(alias="cmsLocaleId", description="Unique identifier of the CMS locale for this item"),
+ ] = None
+ last_published: typing_extensions.Annotated[
+ typing.Optional[dt.datetime], FieldMetadata(alias="lastPublished"), pydantic.Field(alias="lastPublished")
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[dt.datetime], FieldMetadata(alias="lastUpdated"), pydantic.Field(alias="lastUpdated")
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime], FieldMetadata(alias="createdOn"), pydantic.Field(alias="createdOn")
+ ] = None
+ is_archived: typing_extensions.Annotated[
+ typing.Optional[bool], FieldMetadata(alias="isArchived"), pydantic.Field(alias="isArchived")
+ ] = None
+ is_draft: typing_extensions.Annotated[
+ typing.Optional[bool], FieldMetadata(alias="isDraft"), pydantic.Field(alias="isDraft")
+ ] = None
+ field_data: typing_extensions.Annotated[
+ SingleLocaleCreatedPayloadFieldData, FieldMetadata(alias="fieldData"), pydantic.Field(alias="fieldData")
+ ]
+
+ 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/single_locale_created_payload_field_data.py b/src/webflow/types/single_locale_created_payload_field_data.py
new file mode 100644
index 0000000..7306bc9
--- /dev/null
+++ b/src/webflow/types/single_locale_created_payload_field_data.py
@@ -0,0 +1,20 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class SingleLocaleCreatedPayloadFieldData(UniversalBaseModel):
+ name: str
+ slug: str
+
+ 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.py b/src/webflow/types/site.py
index c1bba38..15a4826 100644
--- a/src/webflow/types/site.py
+++ b/src/webflow/types/site.py
@@ -3,53 +3,90 @@
import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .domain import Domain
+from .locales import Locales
+from .site_data_collection_type import SiteDataCollectionType
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+class Site(UniversalBaseModel):
+ id: str = pydantic.Field()
+ """
+ Unique identifier for the Site
+ """
-class Site(pydantic.BaseModel):
- id: str = pydantic.Field(description="Unique identifier for the Site")
- workspace_id: typing.Optional[str] = pydantic.Field(
- alias="workspaceId", default=None, description="Unique identifier for the Workspace"
- )
- created_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="createdOn", default=None, description="Date the Site was created"
- )
- display_name: typing.Optional[str] = pydantic.Field(
- alias="displayName", default=None, description="Name given to Site"
- )
- short_name: typing.Optional[str] = pydantic.Field(
- alias="shortName", default=None, description="Slugified version of name"
- )
- last_published: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastPublished", default=None, description="Date the Site was last published"
- )
- last_updated: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastUpdated", default=None, description="Date the Site was last updated"
- )
- preview_url: typing.Optional[str] = pydantic.Field(
- alias="previewUrl", default=None, description="URL of a generated image for the given Site"
- )
- time_zone: typing.Optional[str] = pydantic.Field(
- alias="timeZone", default=None, description="Site timezone set under Site Settings"
- )
- custom_domains: typing.Optional[typing.List[Domain]] = pydantic.Field(alias="customDomains", default=None)
+ workspace_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="workspaceId"),
+ pydantic.Field(alias="workspaceId", description="Unique identifier for the Workspace"),
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="Date the Site was created"),
+ ] = None
+ display_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="displayName"),
+ pydantic.Field(alias="displayName", description="Name given to Site"),
+ ] = None
+ short_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="shortName"),
+ pydantic.Field(alias="shortName", description="Slugified version of name"),
+ ] = None
+ last_published: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="lastPublished"),
+ pydantic.Field(alias="lastPublished", description="Date the Site was last published"),
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="Date the Site was last updated"),
+ ] = None
+ preview_url: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="previewUrl"),
+ pydantic.Field(alias="previewUrl", description="URL of a generated image for the given Site"),
+ ] = None
+ time_zone: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="timeZone"),
+ pydantic.Field(alias="timeZone", description="Site timezone set under Site Settings"),
+ ] = None
+ parent_folder_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="parentFolderId"),
+ pydantic.Field(alias="parentFolderId", description="The ID of the parent folder the Site exists in"),
+ ] = None
+ custom_domains: typing_extensions.Annotated[
+ typing.Optional[typing.List[Domain]],
+ FieldMetadata(alias="customDomains"),
+ pydantic.Field(alias="customDomains"),
+ ] = None
+ locales: typing.Optional[Locales] = None
+ data_collection_enabled: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="dataCollectionEnabled"),
+ pydantic.Field(
+ alias="dataCollectionEnabled", description="Indicates if data collection is enabled for the site."
+ ),
+ ] = None
+ data_collection_type: typing_extensions.Annotated[
+ typing.Optional[SiteDataCollectionType],
+ FieldMetadata(alias="dataCollectionType"),
+ pydantic.Field(alias="dataCollectionType", description="The type of data collection enabled for the site."),
+ ] = None
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/site_activity_log_item.py b/src/webflow/types/site_activity_log_item.py
index f04b804..cc07cef 100644
--- a/src/webflow/types/site_activity_log_item.py
+++ b/src/webflow/types/site_activity_log_item.py
@@ -3,41 +3,49 @@
import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .site_activity_log_item_event import SiteActivityLogItemEvent
from .site_activity_log_item_resource_operation import SiteActivityLogItemResourceOperation
from .site_activity_log_item_user import SiteActivityLogItemUser
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class SiteActivityLogItem(pydantic.BaseModel):
+class SiteActivityLogItem(UniversalBaseModel):
id: typing.Optional[str] = None
- created_on: typing.Optional[dt.datetime] = pydantic.Field(alias="createdOn", default=None)
- last_updated: typing.Optional[dt.datetime] = pydantic.Field(alias="lastUpdated", default=None)
- event: typing.Optional[str] = None
- resource_operation: typing.Optional[SiteActivityLogItemResourceOperation] = pydantic.Field(
- alias="resourceOperation", default=None
- )
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime], FieldMetadata(alias="createdOn"), pydantic.Field(alias="createdOn")
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[dt.datetime], FieldMetadata(alias="lastUpdated"), pydantic.Field(alias="lastUpdated")
+ ] = None
+ event: typing.Optional[SiteActivityLogItemEvent] = None
+ resource_operation: typing_extensions.Annotated[
+ typing.Optional[SiteActivityLogItemResourceOperation],
+ FieldMetadata(alias="resourceOperation"),
+ pydantic.Field(alias="resourceOperation"),
+ ] = None
user: typing.Optional[SiteActivityLogItemUser] = None
- resource_id: typing.Optional[str] = pydantic.Field(alias="resourceId", default=None)
- resource_name: typing.Optional[str] = pydantic.Field(alias="resourceName", default=None)
- new_value: typing.Optional[str] = pydantic.Field(alias="newValue", default=None)
- previous_value: typing.Optional[str] = pydantic.Field(alias="previousValue", default=None)
+ resource_id: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="resourceId"), pydantic.Field(alias="resourceId")
+ ] = None
+ resource_name: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="resourceName"), pydantic.Field(alias="resourceName")
+ ] = None
+ new_value: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="newValue"), pydantic.Field(alias="newValue")
+ ] = None
+ previous_value: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="previousValue"), pydantic.Field(alias="previousValue")
+ ] = None
payload: typing.Optional[typing.Dict[str, typing.Any]] = None
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/site_activity_log_item_event.py b/src/webflow/types/site_activity_log_item_event.py
new file mode 100644
index 0000000..de7a114
--- /dev/null
+++ b/src/webflow/types/site_activity_log_item_event.py
@@ -0,0 +1,51 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+SiteActivityLogItemEvent = typing.Union[
+ typing.Literal[
+ "styles_modified",
+ "site_published",
+ "ix2_modified_on_page",
+ "page_dom_modified",
+ "cms_item",
+ "backup_created",
+ "page_custom_code_modified",
+ "symbols_modified",
+ "variable_modified",
+ "variables_modified",
+ "cms_collection",
+ "page_settings_modified",
+ "page_settings_custom_code_modified",
+ "ix2_modified_on_component",
+ "ix2_modified_on_class",
+ "site_custom_code_modified",
+ "page_duplicated",
+ "secondary_locale_page_content_modified",
+ "page_renamed",
+ "page_created",
+ "page_deleted",
+ "site_unpublished",
+ "backup_restored",
+ "locale_added",
+ "branch_created",
+ "locale_display_name_updated",
+ "locale_subdirectory_updated",
+ "branch_merged",
+ "locale_tag_updated",
+ "branch_deleted",
+ "locale_enabled",
+ "locale_removed",
+ "locale_disabled",
+ "library_shared",
+ "library_unshared",
+ "library_installed",
+ "library_uninstalled",
+ "library_update_shared",
+ "library_update_accepted",
+ "branch_review_created",
+ "branch_review_approved",
+ "branch_review_canceled",
+ ],
+ typing.Any,
+]
diff --git a/src/webflow/types/site_activity_log_item_resource_operation.py b/src/webflow/types/site_activity_log_item_resource_operation.py
index fef8208..59074a7 100644
--- a/src/webflow/types/site_activity_log_item_resource_operation.py
+++ b/src/webflow/types/site_activity_log_item_resource_operation.py
@@ -1,33 +1,18 @@
# This file was auto-generated by Fern from our API Definition.
-import enum
import typing
-T_Result = typing.TypeVar("T_Result")
-
-
-class SiteActivityLogItemResourceOperation(str, enum.Enum):
- CREATED = "CREATED"
- MODIFIED = "MODIFIED"
- PUBLISHED = "PUBLISHED"
- UNPUBLISHED = "UNPUBLISHED"
- DELETED = "DELETED"
-
- def visit(
- self,
- created: typing.Callable[[], T_Result],
- modified: typing.Callable[[], T_Result],
- published: typing.Callable[[], T_Result],
- unpublished: typing.Callable[[], T_Result],
- deleted: typing.Callable[[], T_Result],
- ) -> T_Result:
- if self is SiteActivityLogItemResourceOperation.CREATED:
- return created()
- if self is SiteActivityLogItemResourceOperation.MODIFIED:
- return modified()
- if self is SiteActivityLogItemResourceOperation.PUBLISHED:
- return published()
- if self is SiteActivityLogItemResourceOperation.UNPUBLISHED:
- return unpublished()
- if self is SiteActivityLogItemResourceOperation.DELETED:
- return deleted()
+SiteActivityLogItemResourceOperation = typing.Union[
+ typing.Literal[
+ "CREATED",
+ "MODIFIED",
+ "PUBLISHED",
+ "UNPUBLISHED",
+ "DELETED",
+ "GROUP_REORDERED",
+ "GROUP_CREATED",
+ "GROUP_DELETED",
+ "REORDERED",
+ ],
+ typing.Any,
+]
diff --git a/src/webflow/types/site_activity_log_item_user.py b/src/webflow/types/site_activity_log_item_user.py
index 66bcfbb..82457cc 100644
--- a/src/webflow/types/site_activity_log_item_user.py
+++ b/src/webflow/types/site_activity_log_item_user.py
@@ -1,30 +1,24 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class SiteActivityLogItemUser(pydantic.BaseModel):
+class SiteActivityLogItemUser(UniversalBaseModel):
id: typing.Optional[str] = None
- display_name: typing.Optional[str] = pydantic.Field(alias="displayName", default=None)
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ display_name: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="displayName"), pydantic.Field(alias="displayName")
+ ] = 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_activity_log_response.py b/src/webflow/types/site_activity_log_response.py
index 06a04ab..5d0cb51 100644
--- a/src/webflow/types/site_activity_log_response.py
+++ b/src/webflow/types/site_activity_log_response.py
@@ -1,31 +1,22 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from .pagination import Pagination
from .site_activity_log_item import SiteActivityLogItem
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class SiteActivityLogResponse(pydantic.BaseModel):
+class SiteActivityLogResponse(UniversalBaseModel):
items: typing.Optional[typing.List[SiteActivityLogItem]] = None
pagination: typing.Optional[Pagination] = None
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/site_data_collection_type.py b/src/webflow/types/site_data_collection_type.py
new file mode 100644
index 0000000..88d6188
--- /dev/null
+++ b/src/webflow/types/site_data_collection_type.py
@@ -0,0 +1,5 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+SiteDataCollectionType = typing.Union[typing.Literal["always", "optOut", "disabled"], typing.Any]
diff --git a/src/webflow/types/site_membership.py b/src/webflow/types/site_membership.py
new file mode 100644
index 0000000..b9def86
--- /dev/null
+++ b/src/webflow/types/site_membership.py
@@ -0,0 +1,58 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .workspace_audit_log_item_payload_site_membership_granular_access import (
+ WorkspaceAuditLogItemPayloadSiteMembershipGranularAccess,
+)
+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,
+)
+
+
+class SiteMembership(UniversalBaseModel):
+ site: typing.Optional[WorkspaceAuditLogItemPayloadSiteMembershipSite] = None
+ target_user: typing_extensions.Annotated[
+ typing.Optional[WorkspaceAuditLogItemPayloadSiteMembershipTargetUser],
+ FieldMetadata(alias="targetUser"),
+ pydantic.Field(alias="targetUser"),
+ ] = None
+ method: typing.Optional[WorkspaceAuditLogItemPayloadSiteMembershipMethod] = None
+ user_type: typing_extensions.Annotated[
+ typing.Optional[WorkspaceAuditLogItemPayloadSiteMembershipUserType],
+ FieldMetadata(alias="userType"),
+ pydantic.Field(alias="userType"),
+ ] = None
+ role_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="roleName"),
+ pydantic.Field(alias="roleName", description="The name of the role that was assigned to the user"),
+ ] = None
+ previous_role_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="previousRoleName"),
+ pydantic.Field(alias="previousRoleName", description="The previous role that the user had"),
+ ] = None
+ granular_access: typing_extensions.Annotated[
+ typing.Optional[WorkspaceAuditLogItemPayloadSiteMembershipGranularAccess],
+ FieldMetadata(alias="granularAccess"),
+ pydantic.Field(alias="granularAccess"),
+ ] = 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.py b/src/webflow/types/site_membership_audit_log_item.py
new file mode 100644
index 0000000..6bb4bc5
--- /dev/null
+++ b/src/webflow/types/site_membership_audit_log_item.py
@@ -0,0 +1,28 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .site_membership import SiteMembership
+from .site_membership_audit_log_item_event_sub_type import SiteMembershipAuditLogItemEventSubType
+
+
+class SiteMembershipAuditLogItem(UniversalBaseModel):
+ event_sub_type: typing_extensions.Annotated[
+ typing.Optional[SiteMembershipAuditLogItemEventSubType],
+ FieldMetadata(alias="eventSubType"),
+ pydantic.Field(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..ff26017
--- /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", "user_granular_access_updated"], typing.Any
+]
diff --git a/src/webflow/types/site_plan.py b/src/webflow/types/site_plan.py
new file mode 100644
index 0000000..f008979
--- /dev/null
+++ b/src/webflow/types/site_plan.py
@@ -0,0 +1,37 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .site_plan_id import SitePlanId
+from .site_plan_name import SitePlanName
+
+
+class SitePlan(UniversalBaseModel):
+ id: typing.Optional[SitePlanId] = pydantic.Field(default=None)
+ """
+ ID of the hosting plan.
+ """
+
+ name: typing.Optional[SitePlanName] = pydantic.Field(default=None)
+ """
+ Name of the hosting plan.
+ """
+
+ pricing_info: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="pricingInfo"),
+ pydantic.Field(alias="pricingInfo", description="URL for more information about Webflow hosting plan pricing."),
+ ] = 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_plan_id.py b/src/webflow/types/site_plan_id.py
new file mode 100644
index 0000000..2d0d676
--- /dev/null
+++ b/src/webflow/types/site_plan_id.py
@@ -0,0 +1,21 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+SitePlanId = typing.Union[
+ typing.Literal[
+ "hosting-basic-v3",
+ "hosting-cms-v3",
+ "hosting-business-v3",
+ "hosting-ecommerce-standard-v2",
+ "hosting-ecommerce-plus-v2",
+ "hosting-ecommerce-advanced-v2",
+ "hosting-basic-v4",
+ "hosting-cms-v4",
+ "hosting-business-v4",
+ "hosting-ecommerce-standard-v3",
+ "hosting-ecommerce-plus-v3",
+ "hosting-ecommerce-advanced-v3",
+ ],
+ typing.Any,
+]
diff --git a/src/webflow/types/site_plan_name.py b/src/webflow/types/site_plan_name.py
new file mode 100644
index 0000000..f892f6c
--- /dev/null
+++ b/src/webflow/types/site_plan_name.py
@@ -0,0 +1,15 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+SitePlanName = typing.Union[
+ typing.Literal[
+ "Basic Hosting",
+ "CMS Hosting",
+ "Business Hosting",
+ "ECommerce Standard Hosting",
+ "ECommerce Plus Hosting",
+ "ECommerce Advanced Hosting",
+ ],
+ typing.Any,
+]
diff --git a/src/webflow/types/site_publish.py b/src/webflow/types/site_publish.py
new file mode 100644
index 0000000..0e94156
--- /dev/null
+++ b/src/webflow/types/site_publish.py
@@ -0,0 +1,34 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .site_publish_payload import SitePublishPayload
+
+
+class SitePublish(UniversalBaseModel):
+ """
+ The Webhook payload for when a Site is published
+ """
+
+ trigger_type: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="triggerType"),
+ pydantic.Field(alias="triggerType", description="The type of event that triggered the request"),
+ ] = None
+ payload: typing.Optional[SitePublishPayload] = pydantic.Field(default=None)
+ """
+ The payload of data sent from Webflow
+ """
+
+ 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_publish_payload.py b/src/webflow/types/site_publish_payload.py
new file mode 100644
index 0000000..3e61145
--- /dev/null
+++ b/src/webflow/types/site_publish_payload.py
@@ -0,0 +1,45 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class SitePublishPayload(UniversalBaseModel):
+ """
+ The payload of data sent from Webflow
+ """
+
+ site_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="siteId"),
+ pydantic.Field(alias="siteId", description="The ID of the site that was published"),
+ ] = None
+ published_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="publishedOn"),
+ pydantic.Field(alias="publishedOn", description="The timestamp of the publish event"),
+ ] = None
+ domains: typing.Optional[typing.List[str]] = pydantic.Field(default=None)
+ """
+ The domains that were published
+ """
+
+ published_by: typing_extensions.Annotated[
+ typing.Optional[typing.Dict[str, typing.Any]],
+ FieldMetadata(alias="publishedBy"),
+ pydantic.Field(alias="publishedBy", description="The name andID of the user who published the site"),
+ ] = 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/sites.py b/src/webflow/types/sites.py
new file mode 100644
index 0000000..f71410b
--- /dev/null
+++ b/src/webflow/types/sites.py
@@ -0,0 +1,20 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .site import Site
+
+
+class Sites(UniversalBaseModel):
+ sites: typing.Optional[typing.List[Site]] = 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/sku.py b/src/webflow/types/sku.py
index a97ee15..f02c4c9 100644
--- a/src/webflow/types/sku.py
+++ b/src/webflow/types/sku.py
@@ -3,44 +3,52 @@
import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .sku_field_data import SkuFieldData
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class Sku(pydantic.BaseModel):
+class Sku(UniversalBaseModel):
"""
The SKU object
"""
- id: typing.Optional[str] = pydantic.Field(default=None, description="Unique identifier for the Product")
- last_published: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastPublished", default=None, description="The date the Product was last published"
- )
- last_updated: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastUpdated", default=None, description="The date the Product was last updated"
- )
- created_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="createdOn", default=None, description="The date the Product was created"
- )
- field_data: typing.Optional[SkuFieldData] = pydantic.Field(
- alias="fieldData", default=None, description="Standard and Custom fields for a SKU"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Unique identifier for the Product
+ """
+
+ cms_locale_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="cmsLocaleId"),
+ pydantic.Field(alias="cmsLocaleId", description="Identifier for the locale of the CMS item"),
+ ] = None
+ last_published: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="lastPublished"),
+ pydantic.Field(alias="lastPublished", description="The date the Product was last published"),
+ ] = None
+ last_updated: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="lastUpdated"),
+ pydantic.Field(alias="lastUpdated", description="The date the Product was last updated"),
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="The date the Product was created"),
+ ] = None
+ field_data: typing_extensions.Annotated[
+ typing.Optional[SkuFieldData], FieldMetadata(alias="fieldData"), pydantic.Field(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/types/sku_field_data.py b/src/webflow/types/sku_field_data.py
index 7143bc3..7cfb6df 100644
--- a/src/webflow/types/sku_field_data.py
+++ b/src/webflow/types/sku_field_data.py
@@ -1,58 +1,84 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
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_field_data_price import SkuFieldDataPrice
+from .sku_property_list import SkuPropertyList
from .sku_value_list import SkuValueList
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class SkuFieldData(pydantic.BaseModel):
+class SkuFieldData(UniversalBaseModel):
"""
Standard and Custom fields for a SKU
"""
- sku_values: typing.Optional[SkuValueList] = pydantic.Field(alias="sku-values", default=None)
- name: str = pydantic.Field(description="Name of the Product")
- slug: str = pydantic.Field(description="URL structure of the Product in your site.")
- price: SkuFieldDataPrice = pydantic.Field(description="price of SKU")
- compare_at_price: typing.Optional[SkuFieldDataCompareAtPrice] = pydantic.Field(
- alias="compare-at-price", default=None, description="comparison price of SKU"
- )
- ec_sku_billing_method: typing.Optional[SkuFieldDataEcSkuBillingMethod] = pydantic.Field(
- alias="ec-sku-billing-method", default=None
- )
- ec_sku_subscription_plan: typing.Optional[SkuFieldDataEcSkuSubscriptionPlan] = pydantic.Field(
- alias="ec-sku-subscription-plan", default=None
- )
- track_inventory: typing.Optional[bool] = pydantic.Field(
- alias="track-inventory",
- default=None,
- description="A boolean indicating whether inventory for this product should be tracked.",
- )
- quantity: typing.Optional[float] = pydantic.Field(
- default=None, description="Quantity of SKU that will be tracked as items are ordered."
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ sku_values: typing_extensions.Annotated[
+ typing.Optional[SkuValueList], FieldMetadata(alias="sku-values"), pydantic.Field(alias="sku-values")
+ ] = None
+ name: str = pydantic.Field()
+ """
+ Name of the Product
+ """
+
+ slug: str = pydantic.Field()
+ """
+ URL structure of the Product in your site.
+ """
+
+ price: SkuFieldDataPrice = pydantic.Field()
+ """
+ price of SKU
+ """
+
+ compare_at_price: typing_extensions.Annotated[
+ typing.Optional[SkuFieldDataCompareAtPrice],
+ FieldMetadata(alias="compare-at-price"),
+ pydantic.Field(alias="compare-at-price", description="comparison price of SKU"),
+ ] = None
+ ec_sku_billing_method: typing_extensions.Annotated[
+ typing.Optional[SkuFieldDataEcSkuBillingMethod],
+ FieldMetadata(alias="ec-sku-billing-method"),
+ pydantic.Field(
+ alias="ec-sku-billing-method",
+ description="[Billing method](https://help.webflow.com/hc/en-us/articles/33961432087955-Add-and-manage-products-and-categories#billing-methods)for the SKU",
+ ),
+ ] = None
+ ec_sku_subscription_plan: typing_extensions.Annotated[
+ typing.Optional[SkuFieldDataEcSkuSubscriptionPlan],
+ FieldMetadata(alias="ec-sku-subscription-plan"),
+ pydantic.Field(
+ alias="ec-sku-subscription-plan",
+ description="[Subscription plan](https://help.webflow.com/hc/en-us/articles/33961432087955-Add-and-manage-products-and-categories#subscription) for the SKU",
+ ),
+ ] = None
+ main_image: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="main-image"),
+ pydantic.Field(alias="main-image", description="The URL for the main image of the SKU"),
+ ] = None
+ 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(alias="sku-properties", description="The properties of the SKU"),
+ ] = 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/sku_field_data_compare_at_price.py b/src/webflow/types/sku_field_data_compare_at_price.py
index 6b85f7a..ba520de 100644
--- a/src/webflow/types/sku_field_data_compare_at_price.py
+++ b/src/webflow/types/sku_field_data_compare_at_price.py
@@ -1,33 +1,31 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class SkuFieldDataCompareAtPrice(pydantic.BaseModel):
+class SkuFieldDataCompareAtPrice(UniversalBaseModel):
"""
comparison price of SKU
"""
- value: typing.Optional[float] = pydantic.Field(default=None, description="Price of SKU")
- unit: typing.Optional[str] = pydantic.Field(default=None, description="Currency of Item")
+ value: typing.Optional[float] = pydantic.Field(default=None)
+ """
+ Price of SKU
+ """
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ unit: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Currency of Item
+ """
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/sku_field_data_ec_sku_billing_method.py b/src/webflow/types/sku_field_data_ec_sku_billing_method.py
index 044f305..e0cbcb4 100644
--- a/src/webflow/types/sku_field_data_ec_sku_billing_method.py
+++ b/src/webflow/types/sku_field_data_ec_sku_billing_method.py
@@ -1,17 +1,5 @@
# This file was auto-generated by Fern from our API Definition.
-import enum
import typing
-T_Result = typing.TypeVar("T_Result")
-
-
-class SkuFieldDataEcSkuBillingMethod(str, enum.Enum):
- ONE_TIME = "one-time"
- SUBSCRIPTION = "subscription"
-
- def visit(self, one_time: typing.Callable[[], T_Result], subscription: typing.Callable[[], T_Result]) -> T_Result:
- if self is SkuFieldDataEcSkuBillingMethod.ONE_TIME:
- return one_time()
- if self is SkuFieldDataEcSkuBillingMethod.SUBSCRIPTION:
- return subscription()
+SkuFieldDataEcSkuBillingMethod = typing.Union[typing.Literal["one-time", "subscription"], typing.Any]
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 e69bcb4..30f60bc 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
@@ -1,33 +1,40 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from .sku_field_data_ec_sku_subscription_plan_interval import SkuFieldDataEcSkuSubscriptionPlanInterval
+from .sku_field_data_ec_sku_subscription_plan_plans_item import SkuFieldDataEcSkuSubscriptionPlanPlansItem
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+class SkuFieldDataEcSkuSubscriptionPlan(UniversalBaseModel):
+ """
+ [Subscription plan](https://help.webflow.com/hc/en-us/articles/33961432087955-Add-and-manage-products-and-categories#subscription) for the SKU
+ """
-class SkuFieldDataEcSkuSubscriptionPlan(pydantic.BaseModel):
- interval: typing.Optional[SkuFieldDataEcSkuSubscriptionPlanInterval] = pydantic.Field(
- default=None, description="Interval of subscription renewal"
- )
- frequency: typing.Optional[float] = pydantic.Field(default=None, description="Frequncy of billing within interval")
- trial: typing.Optional[float] = pydantic.Field(default=None, description="Number of days of a trial")
+ interval: typing.Optional[SkuFieldDataEcSkuSubscriptionPlanInterval] = pydantic.Field(default=None)
+ """
+ Interval of subscription renewal
+ """
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ frequency: typing.Optional[float] = pydantic.Field(default=None)
+ """
+ Frequncy of billing within interval
+ """
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ trial: typing.Optional[float] = pydantic.Field(default=None)
+ """
+ Number of days of a trial
+ """
- class Config:
- frozen = True
- smart_union = True
- json_encoders = {dt.datetime: serialize_datetime}
+ plans: typing.Optional[typing.List[SkuFieldDataEcSkuSubscriptionPlanPlansItem]] = 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/sku_field_data_ec_sku_subscription_plan_interval.py b/src/webflow/types/sku_field_data_ec_sku_subscription_plan_interval.py
index ffa978f..08d8923 100644
--- a/src/webflow/types/sku_field_data_ec_sku_subscription_plan_interval.py
+++ b/src/webflow/types/sku_field_data_ec_sku_subscription_plan_interval.py
@@ -1,33 +1,5 @@
# This file was auto-generated by Fern from our API Definition.
-import enum
import typing
-T_Result = typing.TypeVar("T_Result")
-
-
-class SkuFieldDataEcSkuSubscriptionPlanInterval(str, enum.Enum):
- """
- Interval of subscription renewal
- """
-
- DAY = "day"
- WEEK = "week"
- MONTH = "month"
- YEAR = "year"
-
- def visit(
- self,
- day: typing.Callable[[], T_Result],
- week: typing.Callable[[], T_Result],
- month: typing.Callable[[], T_Result],
- year: typing.Callable[[], T_Result],
- ) -> T_Result:
- if self is SkuFieldDataEcSkuSubscriptionPlanInterval.DAY:
- return day()
- if self is SkuFieldDataEcSkuSubscriptionPlanInterval.WEEK:
- return week()
- if self is SkuFieldDataEcSkuSubscriptionPlanInterval.MONTH:
- return month()
- if self is SkuFieldDataEcSkuSubscriptionPlanInterval.YEAR:
- return year()
+SkuFieldDataEcSkuSubscriptionPlanInterval = typing.Union[typing.Literal["day", "week", "month", "year"], typing.Any]
diff --git a/src/webflow/types/sku_field_data_ec_sku_subscription_plan_plans_item.py b/src/webflow/types/sku_field_data_ec_sku_subscription_plan_plans_item.py
new file mode 100644
index 0000000..0b7c397
--- /dev/null
+++ b/src/webflow/types/sku_field_data_ec_sku_subscription_plan_plans_item.py
@@ -0,0 +1,33 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .sku_field_data_ec_sku_subscription_plan_plans_item_status import SkuFieldDataEcSkuSubscriptionPlanPlansItemStatus
+
+
+class SkuFieldDataEcSkuSubscriptionPlanPlansItem(UniversalBaseModel):
+ platform: typing.Optional[typing.Literal["stripe"]] = pydantic.Field(default=None)
+ """
+ The platform of the subscription plan
+ """
+
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The unique identifier of the plan
+ """
+
+ status: typing.Optional[SkuFieldDataEcSkuSubscriptionPlanPlansItemStatus] = pydantic.Field(default=None)
+ """
+ The status of the plan
+ """
+
+ 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/sku_field_data_ec_sku_subscription_plan_plans_item_status.py b/src/webflow/types/sku_field_data_ec_sku_subscription_plan_plans_item_status.py
new file mode 100644
index 0000000..549e5aa
--- /dev/null
+++ b/src/webflow/types/sku_field_data_ec_sku_subscription_plan_plans_item_status.py
@@ -0,0 +1,7 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+SkuFieldDataEcSkuSubscriptionPlanPlansItemStatus = typing.Union[
+ typing.Literal["active", "inactive", "canceled"], typing.Any
+]
diff --git a/src/webflow/types/sku_field_data_price.py b/src/webflow/types/sku_field_data_price.py
index a588035..17940d7 100644
--- a/src/webflow/types/sku_field_data_price.py
+++ b/src/webflow/types/sku_field_data_price.py
@@ -1,33 +1,36 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class SkuFieldDataPrice(pydantic.BaseModel):
+class SkuFieldDataPrice(UniversalBaseModel):
"""
price of SKU
"""
- value: typing.Optional[float] = pydantic.Field(default=None, description="Price of SKU")
- unit: typing.Optional[str] = pydantic.Field(default=None, description="Currency of Item")
+ value: typing.Optional[float] = pydantic.Field(default=None)
+ """
+ Price of SKU
+ """
+
+ unit: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Currency of Item
+ """
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ currency: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Currency of Item (alternative representation)
+ """
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/sku_property_list.py b/src/webflow/types/sku_property_list.py
index 68acf4a..3602aa4 100644
--- a/src/webflow/types/sku_property_list.py
+++ b/src/webflow/types/sku_property_list.py
@@ -1,37 +1,37 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from .sku_property_list_enum_item import SkuPropertyListEnumItem
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class SkuPropertyList(pydantic.BaseModel):
+class SkuPropertyList(UniversalBaseModel):
"""
A variant/option type for a SKU
"""
- id: str = pydantic.Field(description="Unique identifier for a collection of Product Variants")
- name: str = pydantic.Field(description="Name of the collection of Product Variants")
- enum: typing.List[SkuPropertyListEnumItem] = pydantic.Field(
- description="The individual Product variants that are contained within the collection"
- )
+ id: str = pydantic.Field()
+ """
+ Unique identifier for a collection of Product Variants
+ """
+
+ name: str = pydantic.Field()
+ """
+ Name of the collection of Product Variants
+ """
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ enum: typing.List[SkuPropertyListEnumItem] = pydantic.Field()
+ """
+ The individual Product variants that are contained within the collection
+ """
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/sku_property_list_enum_item.py b/src/webflow/types/sku_property_list_enum_item.py
index e995e4a..2666581 100644
--- a/src/webflow/types/sku_property_list_enum_item.py
+++ b/src/webflow/types/sku_property_list_enum_item.py
@@ -1,34 +1,36 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class SkuPropertyListEnumItem(pydantic.BaseModel):
+class SkuPropertyListEnumItem(UniversalBaseModel):
"""
Enumerated Product variants/Options for the SKU
"""
- id: str = pydantic.Field(description="Unique identifier for a Product variant/Option")
- name: str = pydantic.Field(description="Name of the Product variant/Option")
- slug: str = pydantic.Field(description="Slug for the Product variant/Option in the Site URL structure")
+ id: str = pydantic.Field()
+ """
+ Unique identifier for a Product variant/Option
+ """
+
+ name: str = pydantic.Field()
+ """
+ Name of the Product variant/Option
+ """
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ slug: str = pydantic.Field()
+ """
+ Slug for the Product variant/Option in the Site URL structure
+ """
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/static_field.py b/src/webflow/types/static_field.py
new file mode 100644
index 0000000..714dc5d
--- /dev/null
+++ b/src/webflow/types/static_field.py
@@ -0,0 +1,49 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .static_field_type import StaticFieldType
+
+
+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(alias="isEditable", description="Define whether the field is editable"),
+ ] = None
+ is_required: typing_extensions.Annotated[
+ typing.Optional[bool],
+ FieldMetadata(alias="isRequired"),
+ pydantic.Field(alias="isRequired", description="define whether a field is required in a collection"),
+ ] = None
+ type: StaticFieldType = pydantic.Field()
+ """
+ Choose these appropriate field type for your collection data
+ """
+
+ display_name: typing_extensions.Annotated[
+ str, FieldMetadata(alias="displayName"), pydantic.Field(alias="displayName", description="The name of a field")
+ ]
+ help_text: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="helpText"),
+ pydantic.Field(alias="helpText", description="Additional text to help anyone filling out this field"),
+ ] = 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/static_field_type.py b/src/webflow/types/static_field_type.py
new file mode 100644
index 0000000..e7cadf0
--- /dev/null
+++ b/src/webflow/types/static_field_type.py
@@ -0,0 +1,22 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+StaticFieldType = typing.Union[
+ typing.Literal[
+ "Color",
+ "DateTime",
+ "Email",
+ "File",
+ "Image",
+ "Link",
+ "MultiImage",
+ "Number",
+ "Phone",
+ "PlainText",
+ "RichText",
+ "Switch",
+ "VideoLink",
+ ],
+ typing.Any,
+]
diff --git a/src/webflow/types/stripe_card.py b/src/webflow/types/stripe_card.py
index deb17d0..55580d9 100644
--- a/src/webflow/types/stripe_card.py
+++ b/src/webflow/types/stripe_card.py
@@ -1,46 +1,45 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .stripe_card_brand import StripeCardBrand
from .stripe_card_expires import StripeCardExpires
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class StripeCard(pydantic.BaseModel):
+class StripeCard(UniversalBaseModel):
"""
Details on the card used to fulfill this order, if this order was finalized with Stripe.
"""
- last_4: typing.Optional[str] = pydantic.Field(
- alias="last4", default=None, description="The last 4 digits on the card as a string"
- )
- brand: typing.Optional[StripeCardBrand] = pydantic.Field(
- default=None, description="The card's brand (ie. credit card network)"
- )
- owner_name: typing.Optional[str] = pydantic.Field(
- alias="ownerName", default=None, description="The name on the card."
- )
- expires: typing.Optional[StripeCardExpires] = pydantic.Field(
- default=None, description="The card's expiration date."
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ last_4: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="last4"),
+ pydantic.Field(alias="last4", description="The last 4 digits on the card as a string"),
+ ] = None
+ brand: typing.Optional[StripeCardBrand] = pydantic.Field(default=None)
+ """
+ The card's brand (ie. credit card network)
+ """
+
+ owner_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="ownerName"),
+ pydantic.Field(alias="ownerName", description="The name on the card."),
+ ] = None
+ expires: typing.Optional[StripeCardExpires] = pydantic.Field(default=None)
+ """
+ The card's expiration date.
+ """
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/stripe_card_brand.py b/src/webflow/types/stripe_card_brand.py
index 121ce40..3edc472 100644
--- a/src/webflow/types/stripe_card_brand.py
+++ b/src/webflow/types/stripe_card_brand.py
@@ -1,45 +1,7 @@
# This file was auto-generated by Fern from our API Definition.
-import enum
import typing
-T_Result = typing.TypeVar("T_Result")
-
-
-class StripeCardBrand(str, enum.Enum):
- """
- The card's brand (ie. credit card network)
- """
-
- VISA = "Visa"
- AMERICAN_EXPRESS = "American Express"
- MASTER_CARD = "MasterCard"
- DISCOVER = "Discover"
- JCB = "JCB"
- DINERS_CLUB = "Diners Club"
- UNKNOWN = "Unknown"
-
- def visit(
- self,
- visa: typing.Callable[[], T_Result],
- american_express: typing.Callable[[], T_Result],
- master_card: typing.Callable[[], T_Result],
- discover: typing.Callable[[], T_Result],
- jcb: typing.Callable[[], T_Result],
- diners_club: typing.Callable[[], T_Result],
- unknown: typing.Callable[[], T_Result],
- ) -> T_Result:
- if self is StripeCardBrand.VISA:
- return visa()
- if self is StripeCardBrand.AMERICAN_EXPRESS:
- return american_express()
- if self is StripeCardBrand.MASTER_CARD:
- return master_card()
- if self is StripeCardBrand.DISCOVER:
- return discover()
- if self is StripeCardBrand.JCB:
- return jcb()
- if self is StripeCardBrand.DINERS_CLUB:
- return diners_club()
- if self is StripeCardBrand.UNKNOWN:
- return unknown()
+StripeCardBrand = typing.Union[
+ typing.Literal["Visa", "American Express", "MasterCard", "Discover", "JCB", "Diners Club", "Unknown"], typing.Any
+]
diff --git a/src/webflow/types/stripe_card_expires.py b/src/webflow/types/stripe_card_expires.py
index 793f717..9cf529f 100644
--- a/src/webflow/types/stripe_card_expires.py
+++ b/src/webflow/types/stripe_card_expires.py
@@ -1,33 +1,31 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class StripeCardExpires(pydantic.BaseModel):
+class StripeCardExpires(UniversalBaseModel):
"""
The card's expiration date.
"""
- year: typing.Optional[float] = pydantic.Field(default=None, description="Year that the card expires")
- month: typing.Optional[float] = pydantic.Field(default=None, description="Month that the card expires")
+ year: typing.Optional[float] = pydantic.Field(default=None)
+ """
+ Year that the card expires
+ """
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ month: typing.Optional[float] = pydantic.Field(default=None)
+ """
+ Month that the card expires
+ """
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/stripe_details.py b/src/webflow/types/stripe_details.py
index e71a90d..acd103a 100644
--- a/src/webflow/types/stripe_details.py
+++ b/src/webflow/types/stripe_details.py
@@ -1,56 +1,66 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class StripeDetails(pydantic.BaseModel):
+class StripeDetails(UniversalBaseModel):
"""
An object with various Stripe IDs, useful for linking into the stripe dashboard.
"""
- subscription_id: typing.Optional[str] = pydantic.Field(
- alias="subscriptionId", default=None, description="Stripe-generated identifier for the Subscription"
- )
- payment_method: typing.Optional[str] = pydantic.Field(
- alias="paymentMethod", default=None, description="Stripe-generated identifier for the PaymentMethod used"
- )
- payment_intent_id: typing.Optional[str] = pydantic.Field(
- alias="paymentIntentId", default=None, description="Stripe-generated identifier for the PaymentIntent, or null"
- )
- customer_id: typing.Optional[str] = pydantic.Field(
- alias="customerId", default=None, description="Stripe-generated customer identifier, or null"
- )
- charge_id: typing.Optional[str] = pydantic.Field(
- alias="chargeId", default=None, description="Stripe-generated charge identifier, or null"
- )
- dispute_id: typing.Optional[str] = pydantic.Field(
- alias="disputeId", default=None, description="Stripe-generated dispute identifier, or null"
- )
- refund_id: typing.Optional[str] = pydantic.Field(
- alias="refundId", default=None, description="Stripe-generated refund identifier, or null"
- )
- refund_reason: typing.Optional[str] = pydantic.Field(
- alias="refundReason", default=None, description="Stripe-generated refund reason, or null"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ subscription_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="subscriptionId"),
+ pydantic.Field(alias="subscriptionId", description="Stripe-generated identifier for the Subscription"),
+ ] = None
+ payment_method: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="paymentMethod"),
+ pydantic.Field(alias="paymentMethod", description="Stripe-generated identifier for the PaymentMethod used"),
+ ] = None
+ payment_intent_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="paymentIntentId"),
+ pydantic.Field(
+ alias="paymentIntentId", description="Stripe-generated identifier for the PaymentIntent, or null"
+ ),
+ ] = None
+ customer_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="customerId"),
+ pydantic.Field(alias="customerId", description="Stripe-generated customer identifier, or null"),
+ ] = None
+ charge_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="chargeId"),
+ pydantic.Field(alias="chargeId", description="Stripe-generated charge identifier, or null"),
+ ] = None
+ dispute_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="disputeId"),
+ pydantic.Field(alias="disputeId", description="Stripe-generated dispute identifier, or null"),
+ ] = None
+ refund_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="refundId"),
+ pydantic.Field(alias="refundId", description="Stripe-generated refund identifier, or null"),
+ ] = None
+ refund_reason: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="refundReason"),
+ pydantic.Field(alias="refundReason", description="Stripe-generated refund reason, or null"),
+ ] = None
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ 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..7dc8c94
--- /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.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+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: str = pydantic.Field()
+ """
+ Node UUID
+ """
+
+ value: str = pydantic.Field()
+ """
+ The text content of the submit button.
+ """
+
+ waiting_text: typing_extensions.Annotated[
+ str,
+ FieldMetadata(alias="waitingText"),
+ pydantic.Field(alias="waitingText", description="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/submit_button_node_write.py b/src/webflow/types/submit_button_node_write.py
new file mode 100644
index 0000000..a3066da
--- /dev/null
+++ b/src/webflow/types/submit_button_node_write.py
@@ -0,0 +1,37 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class SubmitButtonNodeWrite(UniversalBaseModel):
+ """
+ Update a submit button node
+ """
+
+ node_id: typing_extensions.Annotated[
+ str, FieldMetadata(alias="nodeId"), pydantic.Field(alias="nodeId", description="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(alias="waitingText", description="The text to show while the form is submitting."),
+ ] = 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/text.py b/src/webflow/types/text.py
new file mode 100644
index 0000000..337db7c
--- /dev/null
+++ b/src/webflow/types/text.py
@@ -0,0 +1,31 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class Text(UniversalBaseModel):
+ """
+ The text content of the node
+ """
+
+ html: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The HTML content of the text node.
+ """
+
+ text: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The raw text content of the text 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..e884b3c
--- /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.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+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: str = pydantic.Field()
+ """
+ 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_input_node_write.py b/src/webflow/types/text_input_node_write.py
new file mode 100644
index 0000000..12515e9
--- /dev/null
+++ b/src/webflow/types/text_input_node_write.py
@@ -0,0 +1,31 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class TextInputNodeWrite(UniversalBaseModel):
+ """
+ Update placeholder text on a text input node
+ """
+
+ node_id: typing_extensions.Annotated[
+ str, FieldMetadata(alias="nodeId"), pydantic.Field(alias="nodeId", description="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_node.py b/src/webflow/types/text_node.py
index e0b9aac..c8fea4b 100644
--- a/src/webflow/types/text_node.py
+++ b/src/webflow/types/text_node.py
@@ -1,33 +1,37 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .text_node_text import TextNodeText
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
+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.
+ """
-class TextNode(pydantic.BaseModel):
+ id: str = pydantic.Field()
"""
- Represents textual content within the DOM. It contains both the raw text and its HTML representation, allowing for flexibility in rendering and processing. Additional attributes can be associated with the text for styling or other purposes.
+ Node UUID
"""
- html: typing.Optional[str] = None
- text: typing.Optional[str] = None
+ text: TextNodeText = pydantic.Field()
+ """
+ The text content of the node
+ """
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
+ attributes: typing.Optional[typing.Dict[str, str]] = pydantic.Field(default=None)
+ """
+ The custom attributes of the node
+ """
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/webflow/types/text_node_text.py b/src/webflow/types/text_node_text.py
new file mode 100644
index 0000000..106d502
--- /dev/null
+++ b/src/webflow/types/text_node_text.py
@@ -0,0 +1,31 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class TextNodeText(UniversalBaseModel):
+ """
+ The text content of the node
+ """
+
+ html: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The HTML content of the text node.
+ """
+
+ text: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The raw text content of the text 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_write.py b/src/webflow/types/text_node_write.py
new file mode 100644
index 0000000..b8ef694
--- /dev/null
+++ b/src/webflow/types/text_node_write.py
@@ -0,0 +1,31 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+
+
+class TextNodeWrite(UniversalBaseModel):
+ """
+ Update a text node
+ """
+
+ node_id: typing_extensions.Annotated[
+ str, FieldMetadata(alias="nodeId"), pydantic.Field(alias="nodeId", description="Node UUID")
+ ]
+ text: 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.
+ """
+
+ 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/trigger_type.py b/src/webflow/types/trigger_type.py
index c8ff70f..5b9e821 100644
--- a/src/webflow/types/trigger_type.py
+++ b/src/webflow/types/trigger_type.py
@@ -1,91 +1,23 @@
# This file was auto-generated by Fern from our API Definition.
-import enum
import typing
-T_Result = typing.TypeVar("T_Result")
-
-
-class TriggerType(str, enum.Enum):
- """
- - `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
- """
-
- FORM_SUBMISSION = "form_submission"
- SITE_PUBLISH = "site_publish"
- PAGE_CREATED = "page_created"
- PAGE_METADATA_UPDATED = "page_metadata_updated"
- PAGE_DELETED = "page_deleted"
- ECOMM_NEW_ORDER = "ecomm_new_order"
- ECOMM_ORDER_CHANGED = "ecomm_order_changed"
- ECOMM_INVENTORY_CHANGED = "ecomm_inventory_changed"
- USER_ACCOUNT_ADDED = "user_account_added"
- USER_ACCOUNT_UPDATED = "user_account_updated"
- USER_ACCOUNT_DELETED = "user_account_deleted"
- COLLECTION_ITEM_CREATED = "collection_item_created"
- COLLECTION_ITEM_CHANGED = "collection_item_changed"
- COLLECTION_ITEM_DELETED = "collection_item_deleted"
- COLLECTION_ITEM_UNPUBLISHED = "collection_item_unpublished"
-
- def visit(
- self,
- form_submission: typing.Callable[[], T_Result],
- site_publish: typing.Callable[[], T_Result],
- page_created: typing.Callable[[], T_Result],
- page_metadata_updated: typing.Callable[[], T_Result],
- page_deleted: typing.Callable[[], T_Result],
- ecomm_new_order: typing.Callable[[], T_Result],
- ecomm_order_changed: typing.Callable[[], T_Result],
- ecomm_inventory_changed: typing.Callable[[], T_Result],
- user_account_added: typing.Callable[[], T_Result],
- user_account_updated: typing.Callable[[], T_Result],
- user_account_deleted: typing.Callable[[], T_Result],
- collection_item_created: typing.Callable[[], T_Result],
- collection_item_changed: typing.Callable[[], T_Result],
- collection_item_deleted: typing.Callable[[], T_Result],
- collection_item_unpublished: typing.Callable[[], T_Result],
- ) -> T_Result:
- if self is TriggerType.FORM_SUBMISSION:
- return form_submission()
- if self is TriggerType.SITE_PUBLISH:
- return site_publish()
- if self is TriggerType.PAGE_CREATED:
- return page_created()
- if self is TriggerType.PAGE_METADATA_UPDATED:
- return page_metadata_updated()
- if self is TriggerType.PAGE_DELETED:
- return page_deleted()
- if self is TriggerType.ECOMM_NEW_ORDER:
- return ecomm_new_order()
- if self is TriggerType.ECOMM_ORDER_CHANGED:
- return ecomm_order_changed()
- if self is TriggerType.ECOMM_INVENTORY_CHANGED:
- return ecomm_inventory_changed()
- if self is TriggerType.USER_ACCOUNT_ADDED:
- return user_account_added()
- if self is TriggerType.USER_ACCOUNT_UPDATED:
- return user_account_updated()
- if self is TriggerType.USER_ACCOUNT_DELETED:
- return user_account_deleted()
- if self is TriggerType.COLLECTION_ITEM_CREATED:
- return collection_item_created()
- if self is TriggerType.COLLECTION_ITEM_CHANGED:
- return collection_item_changed()
- if self is TriggerType.COLLECTION_ITEM_DELETED:
- return collection_item_deleted()
- if self is TriggerType.COLLECTION_ITEM_UNPUBLISHED:
- return collection_item_unpublished()
+TriggerType = typing.Union[
+ typing.Literal[
+ "form_submission",
+ "site_publish",
+ "page_created",
+ "page_metadata_updated",
+ "page_deleted",
+ "ecomm_new_order",
+ "ecomm_order_changed",
+ "ecomm_inventory_changed",
+ "collection_item_created",
+ "collection_item_changed",
+ "collection_item_deleted",
+ "collection_item_published",
+ "collection_item_unpublished",
+ "comment_created",
+ ],
+ typing.Any,
+]
diff --git a/src/webflow/types/updated_order.py b/src/webflow/types/updated_order.py
new file mode 100644
index 0000000..08d0687
--- /dev/null
+++ b/src/webflow/types/updated_order.py
@@ -0,0 +1,31 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .order import Order
+
+
+class UpdatedOrder(UniversalBaseModel):
+ """
+ The Webhook payload for when an order is updated
+ """
+
+ trigger_type: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="triggerType"),
+ pydantic.Field(alias="triggerType", description="The type of event that triggered the request"),
+ ] = None
+ payload: typing.Optional[Order] = 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.py b/src/webflow/types/user.py
deleted file mode 100644
index ec54559..0000000
--- a/src/webflow/types/user.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import datetime as dt
-import typing
-
-from ..core.datetime_utils import serialize_datetime
-from .user_access_groups_item import UserAccessGroupsItem
-from .user_data import UserData
-from .user_status import UserStatus
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class User(pydantic.BaseModel):
- """
- 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: typing.Optional[str] = pydantic.Field(default=None, description="Unique identifier for the User")
- is_email_verified: typing.Optional[bool] = pydantic.Field(
- alias="isEmailVerified", default=None, description="Shows whether the user has verified their email address"
- )
- last_updated: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastUpdated", default=None, description="The timestamp the user was updated"
- )
- invited_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="invitedOn", default=None, description="The timestamp the user was invited"
- )
- created_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="createdOn", default=None, description="The timestamp the user was created"
- )
- last_login: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastLogin", default=None, description="The timestamp the user was logged in"
- )
- status: typing.Optional[UserStatus] = pydantic.Field(default=None, description="The status of the user")
- access_groups: typing.Optional[typing.List[UserAccessGroupsItem]] = pydantic.Field(
- alias="accessGroups", default=None, description="Access groups the user belongs to"
- )
- data: typing.Optional[UserData] = None
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
diff --git a/src/webflow/types/user_access.py b/src/webflow/types/user_access.py
new file mode 100644
index 0000000..0851cd6
--- /dev/null
+++ b/src/webflow/types/user_access.py
@@ -0,0 +1,32 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .workspace_audit_log_item_payload_user_access_method import WorkspaceAuditLogItemPayloadUserAccessMethod
+
+
+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(alias="ipAddress", description="The captured IP address of the user"),
+ ] = 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.py b/src/webflow/types/user_access_audit_log_item.py
new file mode 100644
index 0000000..2d4d877
--- /dev/null
+++ b/src/webflow/types/user_access_audit_log_item.py
@@ -0,0 +1,28 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .user_access import UserAccess
+from .user_access_audit_log_item_event_sub_type import UserAccessAuditLogItemEventSubType
+
+
+class UserAccessAuditLogItem(UniversalBaseModel):
+ event_sub_type: typing_extensions.Annotated[
+ typing.Optional[UserAccessAuditLogItemEventSubType],
+ FieldMetadata(alias="eventSubType"),
+ pydantic.Field(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/user_access_groups_item.py b/src/webflow/types/user_access_groups_item.py
deleted file mode 100644
index 7eeb0f7..0000000
--- a/src/webflow/types/user_access_groups_item.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import datetime as dt
-import typing
-
-from ..core.datetime_utils import serialize_datetime
-from .user_access_groups_item_type import UserAccessGroupsItemType
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class UserAccessGroupsItem(pydantic.BaseModel):
- """
- Access group slugs and types
- """
-
- slug: typing.Optional[str] = pydantic.Field(default=None, description="Access group identifier for APIs")
- type: typing.Optional[UserAccessGroupsItemType] = pydantic.Field(
- default=None,
- description=(
- "The type of access group based on how it was assigned to the user.\n"
- "\n"
- "- `admin` - Assigned to the user via API or in the designer\n"
- "- `ecommerce` - Assigned to the user via an ecommerce purchase\n"
- ),
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- json_encoders = {dt.datetime: serialize_datetime}
diff --git a/src/webflow/types/user_access_groups_item_type.py b/src/webflow/types/user_access_groups_item_type.py
deleted file mode 100644
index f30d5ee..0000000
--- a/src/webflow/types/user_access_groups_item_type.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import enum
-import typing
-
-T_Result = typing.TypeVar("T_Result")
-
-
-class UserAccessGroupsItemType(str, enum.Enum):
- """
- The type of access group based on how it was assigned to the user.
-
- - `admin` - Assigned to the user via API or in the designer
- - `ecommerce` - Assigned to the user via an ecommerce purchase
- """
-
- ADMIN = "admin"
- ECOMMERCE = "ecommerce"
-
- def visit(self, admin: typing.Callable[[], T_Result], ecommerce: typing.Callable[[], T_Result]) -> T_Result:
- if self is UserAccessGroupsItemType.ADMIN:
- return admin()
- if self is UserAccessGroupsItemType.ECOMMERCE:
- return ecommerce()
diff --git a/src/webflow/types/user_data.py b/src/webflow/types/user_data.py
deleted file mode 100644
index d28d82e..0000000
--- a/src/webflow/types/user_data.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import datetime as dt
-import typing
-
-from ..core.datetime_utils import serialize_datetime
-from .user_data_data import UserDataData
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class UserData(pydantic.BaseModel):
- """
- An object containing the User's basic info and custom fields
- """
-
- data: typing.Optional[UserDataData] = None
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- json_encoders = {dt.datetime: serialize_datetime}
diff --git a/src/webflow/types/user_data_data.py b/src/webflow/types/user_data_data.py
deleted file mode 100644
index b58ade7..0000000
--- a/src/webflow/types/user_data_data.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import datetime as dt
-import typing
-
-from ..core.datetime_utils import serialize_datetime
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class UserDataData(pydantic.BaseModel):
- name: typing.Optional[str] = pydantic.Field(default=None, description="The name of the user")
- email: typing.Optional[str] = pydantic.Field(default=None, description="The email address of the user")
- accept_privacy: typing.Optional[bool] = pydantic.Field(
- alias="accept-privacy",
- default=None,
- description="Boolean indicating if the user has accepted the privacy policy",
- )
- accept_communications: typing.Optional[bool] = pydantic.Field(
- alias="accept-communications",
- default=None,
- description="Boolean indicating if the user has accepted to receive communications",
- )
- additional_properties: typing.Optional[str] = pydantic.Field(
- alias="additionalProperties", default=None, description="Custom user attributes"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
diff --git a/src/webflow/types/user_limit_reached.py b/src/webflow/types/user_limit_reached.py
deleted file mode 100644
index e5685fe..0000000
--- a/src/webflow/types/user_limit_reached.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import datetime as dt
-import typing
-
-from ..core.datetime_utils import serialize_datetime
-from .error_details_item import ErrorDetailsItem
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class UserLimitReached(pydantic.BaseModel):
- code: typing.Optional[str] = pydantic.Field(default=None, description="Error code")
- message: typing.Optional[str] = pydantic.Field(default=None, description="Error message")
- external_reference: typing.Optional[str] = pydantic.Field(
- alias="externalReference", default=None, description="Link to more information"
- )
- details: typing.Optional[typing.List[ErrorDetailsItem]] = pydantic.Field(
- default=None, description="Array of errors"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
diff --git a/src/webflow/types/user_list.py b/src/webflow/types/user_list.py
deleted file mode 100644
index 5c2b5a2..0000000
--- a/src/webflow/types/user_list.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import datetime as dt
-import typing
-
-from ..core.datetime_utils import serialize_datetime
-from .user import User
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class UserList(pydantic.BaseModel):
- """
- The list users results
- """
-
- count: typing.Optional[float] = pydantic.Field(default=None, description="Number of users returned")
- limit: typing.Optional[float] = pydantic.Field(default=None, description="The limit specified in the request")
- offset: typing.Optional[float] = pydantic.Field(default=None, description="The offset specified for pagination")
- total: typing.Optional[float] = pydantic.Field(default=None, description="Total number of users in the collection")
- users: typing.Optional[typing.List[User]] = pydantic.Field(default=None, description="List of Users for a Site")
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- json_encoders = {dt.datetime: serialize_datetime}
diff --git a/src/webflow/types/user_status.py b/src/webflow/types/user_status.py
deleted file mode 100644
index 76af17c..0000000
--- a/src/webflow/types/user_status.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import enum
-import typing
-
-T_Result = typing.TypeVar("T_Result")
-
-
-class UserStatus(str, enum.Enum):
- """
- The status of the user
- """
-
- INVITED = "invited"
- VERIFIED = "verified"
- UNVERIFIED = "unverified"
-
- def visit(
- self,
- invited: typing.Callable[[], T_Result],
- verified: typing.Callable[[], T_Result],
- unverified: typing.Callable[[], T_Result],
- ) -> T_Result:
- if self is UserStatus.INVITED:
- return invited()
- if self is UserStatus.VERIFIED:
- return verified()
- if self is UserStatus.UNVERIFIED:
- return unverified()
diff --git a/src/webflow/types/users_not_enabled.py b/src/webflow/types/users_not_enabled.py
deleted file mode 100644
index c2959c6..0000000
--- a/src/webflow/types/users_not_enabled.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import datetime as dt
-import typing
-
-from ..core.datetime_utils import serialize_datetime
-from .error_details_item import ErrorDetailsItem
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class UsersNotEnabled(pydantic.BaseModel):
- code: typing.Optional[str] = pydantic.Field(default=None, description="Error code")
- message: typing.Optional[str] = pydantic.Field(default=None, description="Error message")
- external_reference: typing.Optional[str] = pydantic.Field(
- alias="externalReference", default=None, description="Link to more information"
- )
- details: typing.Optional[typing.List[ErrorDetailsItem]] = pydantic.Field(
- default=None, description="Array of errors"
- )
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
diff --git a/src/webflow/types/webhook.py b/src/webflow/types/webhook.py
index 29dff3c..43f561a 100644
--- a/src/webflow/types/webhook.py
+++ b/src/webflow/types/webhook.py
@@ -3,50 +3,61 @@
import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
from .trigger_type import TriggerType
-
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-
-class Webhook(pydantic.BaseModel):
- id: typing.Optional[str] = pydantic.Field(
- default=None, description="Unique identifier for the Webhook registration"
- )
- workspace_id: typing.Optional[str] = pydantic.Field(
- alias="workspaceId",
- default=None,
- description="Unique identifier for the Workspace the Webhook is registered in",
- )
- site_id: typing.Optional[str] = pydantic.Field(
- alias="siteId", default=None, description="Unique identifier for the Site the Webhook is registered in"
- )
- trigger_type: typing.Optional[TriggerType] = pydantic.Field(alias="triggerType", default=None)
- filter: typing.Optional[typing.Dict[str, typing.Any]] = pydantic.Field(
- default=None,
- description="Filter for selecting which events you want Webhooks to be sent for. Only supported for form_submission trigger types.",
- )
- last_triggered: typing.Optional[dt.datetime] = pydantic.Field(
- alias="lastTriggered", default=None, description="Date the Webhook instance was last triggered"
- )
- created_on: typing.Optional[dt.datetime] = pydantic.Field(
- alias="createdOn", default=None, description="Date the Webhook registration was created"
- )
- url: typing.Optional[str] = pydantic.Field(default=None, description="URL to send the Webhook payload to")
-
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
-
- class Config:
- frozen = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+from .webhook_filter import WebhookFilter
+
+
+class Webhook(UniversalBaseModel):
+ id: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Unique identifier for the Webhook registration
+ """
+
+ trigger_type: typing_extensions.Annotated[
+ typing.Optional[TriggerType], FieldMetadata(alias="triggerType"), pydantic.Field(alias="triggerType")
+ ] = None
+ url: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ URL to send the Webhook payload to
+ """
+
+ workspace_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="workspaceId"),
+ pydantic.Field(
+ alias="workspaceId", description="Unique identifier for the Workspace the Webhook is registered in"
+ ),
+ ] = None
+ site_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="siteId"),
+ pydantic.Field(alias="siteId", description="Unique identifier for the Site the Webhook is registered in"),
+ ] = None
+ filter: typing.Optional[WebhookFilter] = pydantic.Field(default=None)
+ """
+ Only supported for the `form_submission` trigger type. Filter for the form you want Webhooks to be sent for.
+ """
+
+ last_triggered: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="lastTriggered"),
+ pydantic.Field(alias="lastTriggered", description="Date the Webhook instance was last triggered"),
+ ] = None
+ created_on: typing_extensions.Annotated[
+ typing.Optional[dt.datetime],
+ FieldMetadata(alias="createdOn"),
+ pydantic.Field(alias="createdOn", description="Date the Webhook registration was created"),
+ ] = 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/webhook_filter.py b/src/webflow/types/webhook_filter.py
new file mode 100644
index 0000000..2f47255
--- /dev/null
+++ b/src/webflow/types/webhook_filter.py
@@ -0,0 +1,26 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class WebhookFilter(UniversalBaseModel):
+ """
+ Only supported for the `form_submission` trigger type. Filter for the form you want Webhooks to be sent for.
+ """
+
+ name: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ The name of the form you'd like to recieve notifications for.
+ """
+
+ 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/webhook_list.py b/src/webflow/types/webhook_list.py
index 62f5dd2..6d76207 100644
--- a/src/webflow/types/webhook_list.py
+++ b/src/webflow/types/webhook_list.py
@@ -1,31 +1,22 @@
# This file was auto-generated by Fern from our API Definition.
-import datetime as dt
import typing
-from ..core.datetime_utils import serialize_datetime
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from .pagination import Pagination
from .webhook import Webhook
-try:
- import pydantic.v1 as pydantic # type: ignore
-except ImportError:
- import pydantic # type: ignore
-
-class WebhookList(pydantic.BaseModel):
- pagination: typing.Optional[Pagination] = None
+class WebhookList(UniversalBaseModel):
webhooks: typing.Optional[typing.List[Webhook]] = None
+ pagination: typing.Optional[Pagination] = None
- def json(self, **kwargs: typing.Any) -> str:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().json(**kwargs_with_defaults)
-
- def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
- kwargs_with_defaults: typing.Any = {"by_alias": True, "exclude_unset": True, **kwargs}
- return super().dict(**kwargs_with_defaults)
+ 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
- json_encoders = {dt.datetime: serialize_datetime}
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
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..7d3a3c5
--- /dev/null
+++ b/src/webflow/types/workspace_audit_log_item.py
@@ -0,0 +1,178 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from __future__ import annotations
+
+import datetime as dt
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .custom_role import CustomRole
+from .custom_role_audit_log_item_event_sub_type import CustomRoleAuditLogItemEventSubType
+from .setting_change import SettingChange
+from .site_membership import SiteMembership
+from .site_membership_audit_log_item_event_sub_type import SiteMembershipAuditLogItemEventSubType
+from .user_access import UserAccess
+from .user_access_audit_log_item_event_sub_type import UserAccessAuditLogItemEventSubType
+from .workspace_audit_log_item_actor import WorkspaceAuditLogItemActor
+from .workspace_audit_log_item_workspace import WorkspaceAuditLogItemWorkspace
+from .workspace_invitation import WorkspaceInvitation
+from .workspace_invitation_audit_log_item_event_sub_type import WorkspaceInvitationAuditLogItemEventSubType
+from .workspace_membership import WorkspaceMembership
+from .workspace_membership_audit_log_item_event_sub_type import WorkspaceMembershipAuditLogItemEventSubType
+
+
+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"), pydantic.Field(alias="eventType")
+ ] = "user_access"
+ event_sub_type: typing_extensions.Annotated[
+ typing.Optional[UserAccessAuditLogItemEventSubType],
+ FieldMetadata(alias="eventSubType"),
+ pydantic.Field(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"), pydantic.Field(alias="eventType")
+ ] = "custom_role"
+ event_sub_type: typing_extensions.Annotated[
+ typing.Optional[CustomRoleAuditLogItemEventSubType],
+ FieldMetadata(alias="eventSubType"),
+ pydantic.Field(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"), pydantic.Field(alias="eventType")
+ ] = "workspace_membership"
+ event_sub_type: typing_extensions.Annotated[
+ typing.Optional[WorkspaceMembershipAuditLogItemEventSubType],
+ FieldMetadata(alias="eventSubType"),
+ pydantic.Field(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"), pydantic.Field(alias="eventType")
+ ] = "site_membership"
+ event_sub_type: typing_extensions.Annotated[
+ typing.Optional[SiteMembershipAuditLogItemEventSubType],
+ FieldMetadata(alias="eventSubType"),
+ pydantic.Field(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"), pydantic.Field(alias="eventType")
+ ] = "workspace_invitation"
+ event_sub_type: typing_extensions.Annotated[
+ typing.Optional[WorkspaceInvitationAuditLogItemEventSubType],
+ FieldMetadata(alias="eventSubType"),
+ pydantic.Field(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
+
+
+class WorkspaceAuditLogItem_WorkspaceSetting(Base):
+ event_type: typing_extensions.Annotated[
+ typing.Literal["workspace_setting"], FieldMetadata(alias="eventType"), pydantic.Field(alias="eventType")
+ ] = "workspace_setting"
+ event_sub_type: typing_extensions.Annotated[
+ typing.Optional[typing.Literal["setting_updated"]],
+ FieldMetadata(alias="eventSubType"),
+ pydantic.Field(alias="eventSubType"),
+ ] = None
+ payload: typing.Optional[SettingChange] = 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_extensions.Annotated[
+ typing.Union[
+ WorkspaceAuditLogItem_UserAccess,
+ WorkspaceAuditLogItem_CustomRole,
+ WorkspaceAuditLogItem_WorkspaceMembership,
+ WorkspaceAuditLogItem_SiteMembership,
+ WorkspaceAuditLogItem_WorkspaceInvitation,
+ WorkspaceAuditLogItem_WorkspaceSetting,
+ ],
+ pydantic.Field(discriminator="event_type"),
+]
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..ced7149
--- /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.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+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_setting_change_method.py b/src/webflow/types/workspace_audit_log_item_payload_setting_change_method.py
new file mode 100644
index 0000000..4b91759
--- /dev/null
+++ b/src/webflow/types/workspace_audit_log_item_payload_setting_change_method.py
@@ -0,0 +1,5 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+WorkspaceAuditLogItemPayloadSettingChangeMethod = typing.Union[typing.Literal["dashboard", "admin"], typing.Any]
diff --git a/src/webflow/types/workspace_audit_log_item_payload_site_membership_granular_access.py b/src/webflow/types/workspace_audit_log_item_payload_site_membership_granular_access.py
new file mode 100644
index 0000000..82f561d
--- /dev/null
+++ b/src/webflow/types/workspace_audit_log_item_payload_site_membership_granular_access.py
@@ -0,0 +1,22 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class WorkspaceAuditLogItemPayloadSiteMembershipGranularAccess(UniversalBaseModel):
+ id: typing.Optional[str] = None
+ name: typing.Optional[str] = None
+ type: typing.Optional[typing.Literal["cms"]] = None
+ restricted: typing.Optional[bool] = 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..a13fbae
--- /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", "access_request"], 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..bb6df69
--- /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.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+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..cf8e343
--- /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.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+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..9003721
--- /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.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+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_target_users_item.py b/src/webflow/types/workspace_audit_log_item_payload_workspace_invitation_target_users_item.py
new file mode 100644
index 0000000..c18c694
--- /dev/null
+++ b/src/webflow/types/workspace_audit_log_item_payload_workspace_invitation_target_users_item.py
@@ -0,0 +1,20 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+class WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUsersItem(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..df8982f
--- /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", "access_request"], 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..b2adafa
--- /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.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+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..81c18ac
--- /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.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+
+
+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..e31a69e
--- /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.
+
+import typing
+
+import pydantic
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .pagination import Pagination
+from .workspace_audit_log_item import WorkspaceAuditLogItem
+
+
+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..a8a99f5
--- /dev/null
+++ b/src/webflow/types/workspace_invitation.py
@@ -0,0 +1,58 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .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_target_users_item import (
+ WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUsersItem,
+)
+from .workspace_audit_log_item_payload_workspace_invitation_user_type import (
+ WorkspaceAuditLogItemPayloadWorkspaceInvitationUserType,
+)
+
+
+class WorkspaceInvitation(UniversalBaseModel):
+ target_user: typing_extensions.Annotated[
+ typing.Optional[WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUser],
+ FieldMetadata(alias="targetUser"),
+ pydantic.Field(alias="targetUser"),
+ ] = None
+ method: typing.Optional[WorkspaceAuditLogItemPayloadWorkspaceInvitationMethod] = None
+ user_type: typing_extensions.Annotated[
+ typing.Optional[WorkspaceAuditLogItemPayloadWorkspaceInvitationUserType],
+ FieldMetadata(alias="userType"),
+ pydantic.Field(alias="userType"),
+ ] = None
+ role_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="roleName"),
+ pydantic.Field(alias="roleName", description="The name of the role that was assigned to the user"),
+ ] = None
+ previous_role_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="previousRoleName"),
+ pydantic.Field(alias="previousRoleName", description="The previous role that the user had"),
+ ] = None
+ target_users: typing_extensions.Annotated[
+ typing.Optional[typing.List[WorkspaceAuditLogItemPayloadWorkspaceInvitationTargetUsersItem]],
+ FieldMetadata(alias="targetUsers"),
+ pydantic.Field(alias="targetUsers"),
+ ] = 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.py b/src/webflow/types/workspace_invitation_audit_log_item.py
new file mode 100644
index 0000000..7b57c27
--- /dev/null
+++ b/src/webflow/types/workspace_invitation_audit_log_item.py
@@ -0,0 +1,28 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .workspace_invitation import WorkspaceInvitation
+from .workspace_invitation_audit_log_item_event_sub_type import WorkspaceInvitationAuditLogItemEventSubType
+
+
+class WorkspaceInvitationAuditLogItem(UniversalBaseModel):
+ event_sub_type: typing_extensions.Annotated[
+ typing.Optional[WorkspaceInvitationAuditLogItemEventSubType],
+ FieldMetadata(alias="eventSubType"),
+ pydantic.Field(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..07ccddb
--- /dev/null
+++ b/src/webflow/types/workspace_invitation_audit_log_item_event_sub_type.py
@@ -0,0 +1,15 @@
+# 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",
+ "access_request_accepted",
+ ],
+ typing.Any,
+]
diff --git a/src/webflow/types/workspace_membership.py b/src/webflow/types/workspace_membership.py
new file mode 100644
index 0000000..b5996f7
--- /dev/null
+++ b/src/webflow/types/workspace_membership.py
@@ -0,0 +1,50 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .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,
+)
+
+
+class WorkspaceMembership(UniversalBaseModel):
+ target_user: typing_extensions.Annotated[
+ typing.Optional[WorkspaceAuditLogItemPayloadWorkspaceMembershipTargetUser],
+ FieldMetadata(alias="targetUser"),
+ pydantic.Field(alias="targetUser"),
+ ] = None
+ method: typing.Optional[WorkspaceAuditLogItemPayloadWorkspaceMembershipMethod] = None
+ user_type: typing_extensions.Annotated[
+ typing.Optional[WorkspaceAuditLogItemPayloadWorkspaceMembershipUserType],
+ FieldMetadata(alias="userType"),
+ pydantic.Field(alias="userType"),
+ ] = None
+ role_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="roleName"),
+ pydantic.Field(alias="roleName", description="The name of the role that was assigned to the user"),
+ ] = None
+ previous_role_name: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="previousRoleName"),
+ pydantic.Field(alias="previousRoleName", description="The previous role that the user had"),
+ ] = 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.py b/src/webflow/types/workspace_membership_audit_log_item.py
new file mode 100644
index 0000000..20dab22
--- /dev/null
+++ b/src/webflow/types/workspace_membership_audit_log_item.py
@@ -0,0 +1,28 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ..core.serialization import FieldMetadata
+from .workspace_membership import WorkspaceMembership
+from .workspace_membership_audit_log_item_event_sub_type import WorkspaceMembershipAuditLogItemEventSubType
+
+
+class WorkspaceMembershipAuditLogItem(UniversalBaseModel):
+ event_sub_type: typing_extensions.Annotated[
+ typing.Optional[WorkspaceMembershipAuditLogItemEventSubType],
+ FieldMetadata(alias="eventSubType"),
+ pydantic.Field(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/src/webflow/version.py b/src/webflow/version.py
new file mode 100644
index 0000000..f29b4ca
--- /dev/null
+++ b/src/webflow/version.py
@@ -0,0 +1,3 @@
+from importlib import metadata
+
+__version__ = metadata.version("webflow")
diff --git a/tests/__init__.py b/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/test_client.py b/tests/custom/test_client.py
similarity index 86%
rename from tests/test_client.py
rename to tests/custom/test_client.py
index 60a58e6..ab04ce6 100644
--- a/tests/test_client.py
+++ b/tests/custom/test_client.py
@@ -1,6 +1,7 @@
import pytest
+
# Get started with writing tests with pytest at https://docs.pytest.org
@pytest.mark.skip(reason="Unimplemented")
def test_client() -> None:
- assert True == True
+ assert True
diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py
new file mode 100644
index 0000000..f3ea265
--- /dev/null
+++ b/tests/utils/__init__.py
@@ -0,0 +1,2 @@
+# This file was auto-generated by Fern from our API Definition.
+
diff --git a/tests/utils/assets/models/__init__.py b/tests/utils/assets/models/__init__.py
new file mode 100644
index 0000000..2cf0126
--- /dev/null
+++ b/tests/utils/assets/models/__init__.py
@@ -0,0 +1,21 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# This file was auto-generated by Fern from our API Definition.
+
+from .circle import CircleParams
+from .object_with_defaults import ObjectWithDefaultsParams
+from .object_with_optional_field import ObjectWithOptionalFieldParams
+from .shape import Shape_CircleParams, Shape_SquareParams, ShapeParams
+from .square import SquareParams
+from .undiscriminated_shape import UndiscriminatedShapeParams
+
+__all__ = [
+ "CircleParams",
+ "ObjectWithDefaultsParams",
+ "ObjectWithOptionalFieldParams",
+ "ShapeParams",
+ "Shape_CircleParams",
+ "Shape_SquareParams",
+ "SquareParams",
+ "UndiscriminatedShapeParams",
+]
diff --git a/tests/utils/assets/models/circle.py b/tests/utils/assets/models/circle.py
new file mode 100644
index 0000000..9295a33
--- /dev/null
+++ b/tests/utils/assets/models/circle.py
@@ -0,0 +1,11 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# This file was auto-generated by Fern from our API Definition.
+
+import typing_extensions
+
+from webflow.core.serialization import FieldMetadata
+
+
+class CircleParams(typing_extensions.TypedDict):
+ radius_measurement: typing_extensions.Annotated[float, FieldMetadata(alias="radiusMeasurement")]
diff --git a/tests/utils/assets/models/color.py b/tests/utils/assets/models/color.py
new file mode 100644
index 0000000..2aa2c4c
--- /dev/null
+++ b/tests/utils/assets/models/color.py
@@ -0,0 +1,7 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+Color = typing.Union[typing.Literal["red", "blue"], typing.Any]
diff --git a/tests/utils/assets/models/object_with_defaults.py b/tests/utils/assets/models/object_with_defaults.py
new file mode 100644
index 0000000..a977b1d
--- /dev/null
+++ b/tests/utils/assets/models/object_with_defaults.py
@@ -0,0 +1,15 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# This file was auto-generated by Fern from our API Definition.
+
+import typing_extensions
+
+
+class ObjectWithDefaultsParams(typing_extensions.TypedDict):
+ """
+ Defines properties with default values and validation rules.
+ """
+
+ decimal: typing_extensions.NotRequired[float]
+ string: typing_extensions.NotRequired[str]
+ required_string: str
diff --git a/tests/utils/assets/models/object_with_optional_field.py b/tests/utils/assets/models/object_with_optional_field.py
new file mode 100644
index 0000000..f1a588e
--- /dev/null
+++ b/tests/utils/assets/models/object_with_optional_field.py
@@ -0,0 +1,35 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+import uuid
+
+import typing_extensions
+from .color import Color
+from .shape import ShapeParams
+from .undiscriminated_shape import UndiscriminatedShapeParams
+
+from webflow.core.serialization import FieldMetadata
+
+
+class ObjectWithOptionalFieldParams(typing_extensions.TypedDict):
+ literal: typing.Literal["lit_one"]
+ string: typing_extensions.NotRequired[str]
+ integer: typing_extensions.NotRequired[int]
+ long_: typing_extensions.NotRequired[typing_extensions.Annotated[int, FieldMetadata(alias="long")]]
+ double: typing_extensions.NotRequired[float]
+ bool_: typing_extensions.NotRequired[typing_extensions.Annotated[bool, FieldMetadata(alias="bool")]]
+ datetime: typing_extensions.NotRequired[dt.datetime]
+ date: typing_extensions.NotRequired[dt.date]
+ uuid_: typing_extensions.NotRequired[typing_extensions.Annotated[uuid.UUID, FieldMetadata(alias="uuid")]]
+ base_64: typing_extensions.NotRequired[typing_extensions.Annotated[str, FieldMetadata(alias="base64")]]
+ list_: typing_extensions.NotRequired[typing_extensions.Annotated[typing.Sequence[str], FieldMetadata(alias="list")]]
+ set_: typing_extensions.NotRequired[typing_extensions.Annotated[typing.Set[str], FieldMetadata(alias="set")]]
+ map_: typing_extensions.NotRequired[typing_extensions.Annotated[typing.Dict[int, str], FieldMetadata(alias="map")]]
+ enum: typing_extensions.NotRequired[Color]
+ union: typing_extensions.NotRequired[ShapeParams]
+ second_union: typing_extensions.NotRequired[ShapeParams]
+ undiscriminated_union: typing_extensions.NotRequired[UndiscriminatedShapeParams]
+ any: typing.Optional[typing.Any]
diff --git a/tests/utils/assets/models/shape.py b/tests/utils/assets/models/shape.py
new file mode 100644
index 0000000..84153dc
--- /dev/null
+++ b/tests/utils/assets/models/shape.py
@@ -0,0 +1,28 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# This file was auto-generated by Fern from our API Definition.
+
+from __future__ import annotations
+
+import typing
+
+import typing_extensions
+
+from webflow.core.serialization import FieldMetadata
+
+
+class Base(typing_extensions.TypedDict):
+ id: str
+
+
+class Shape_CircleParams(Base):
+ shape_type: typing_extensions.Annotated[typing.Literal["circle"], FieldMetadata(alias="shapeType")]
+ radius_measurement: typing_extensions.Annotated[float, FieldMetadata(alias="radiusMeasurement")]
+
+
+class Shape_SquareParams(Base):
+ shape_type: typing_extensions.Annotated[typing.Literal["square"], FieldMetadata(alias="shapeType")]
+ length_measurement: typing_extensions.Annotated[float, FieldMetadata(alias="lengthMeasurement")]
+
+
+ShapeParams = typing.Union[Shape_CircleParams, Shape_SquareParams]
diff --git a/tests/utils/assets/models/square.py b/tests/utils/assets/models/square.py
new file mode 100644
index 0000000..3f40c1f
--- /dev/null
+++ b/tests/utils/assets/models/square.py
@@ -0,0 +1,11 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# This file was auto-generated by Fern from our API Definition.
+
+import typing_extensions
+
+from webflow.core.serialization import FieldMetadata
+
+
+class SquareParams(typing_extensions.TypedDict):
+ length_measurement: typing_extensions.Annotated[float, FieldMetadata(alias="lengthMeasurement")]
diff --git a/tests/utils/assets/models/undiscriminated_shape.py b/tests/utils/assets/models/undiscriminated_shape.py
new file mode 100644
index 0000000..99f12b3
--- /dev/null
+++ b/tests/utils/assets/models/undiscriminated_shape.py
@@ -0,0 +1,10 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from .circle import CircleParams
+from .square import SquareParams
+
+UndiscriminatedShapeParams = typing.Union[CircleParams, SquareParams]
diff --git a/tests/utils/test_http_client.py b/tests/utils/test_http_client.py
new file mode 100644
index 0000000..10ef8a1
--- /dev/null
+++ b/tests/utils/test_http_client.py
@@ -0,0 +1,300 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from typing import Any, Dict
+
+import pytest
+
+from webflow.core.http_client import (
+ AsyncHttpClient,
+ HttpClient,
+ _build_url,
+ get_request_body,
+ remove_none_from_dict,
+)
+from webflow.core.request_options import RequestOptions
+
+
+# Stub clients for testing HttpClient and AsyncHttpClient
+class _DummySyncClient:
+ """A minimal stub for httpx.Client that records request arguments."""
+
+ def __init__(self) -> None:
+ self.last_request_kwargs: Dict[str, Any] = {}
+
+ def request(self, **kwargs: Any) -> "_DummyResponse":
+ self.last_request_kwargs = kwargs
+ return _DummyResponse()
+
+
+class _DummyAsyncClient:
+ """A minimal stub for httpx.AsyncClient that records request arguments."""
+
+ def __init__(self) -> None:
+ self.last_request_kwargs: Dict[str, Any] = {}
+
+ async def request(self, **kwargs: Any) -> "_DummyResponse":
+ self.last_request_kwargs = kwargs
+ return _DummyResponse()
+
+
+class _DummyResponse:
+ """A minimal stub for httpx.Response."""
+
+ status_code = 200
+ headers: Dict[str, str] = {}
+
+
+def get_request_options() -> RequestOptions:
+ return {"additional_body_parameters": {"see you": "later"}}
+
+
+def get_request_options_with_none() -> RequestOptions:
+ return {"additional_body_parameters": {"see you": "later", "optional": None}}
+
+
+def test_get_json_request_body() -> None:
+ json_body, data_body = get_request_body(json={"hello": "world"}, data=None, request_options=None, omit=None)
+ assert json_body == {"hello": "world"}
+ assert data_body is None
+
+ json_body_extras, data_body_extras = get_request_body(
+ json={"goodbye": "world"}, data=None, request_options=get_request_options(), omit=None
+ )
+
+ assert json_body_extras == {"goodbye": "world", "see you": "later"}
+ assert data_body_extras is None
+
+
+def test_get_files_request_body() -> None:
+ json_body, data_body = get_request_body(json=None, data={"hello": "world"}, request_options=None, omit=None)
+ assert data_body == {"hello": "world"}
+ assert json_body is None
+
+ json_body_extras, data_body_extras = get_request_body(
+ json=None, data={"goodbye": "world"}, request_options=get_request_options(), omit=None
+ )
+
+ assert data_body_extras == {"goodbye": "world", "see you": "later"}
+ assert json_body_extras is None
+
+
+def test_get_none_request_body() -> None:
+ json_body, data_body = get_request_body(json=None, data=None, request_options=None, omit=None)
+ assert data_body is None
+ assert json_body is None
+
+ json_body_extras, data_body_extras = get_request_body(
+ json=None, data=None, request_options=get_request_options(), omit=None
+ )
+
+ assert json_body_extras == {"see you": "later"}
+ assert data_body_extras is None
+
+
+def test_get_empty_json_request_body() -> None:
+ """Test that implicit empty bodies (json=None) are collapsed to None."""
+ unrelated_request_options: RequestOptions = {"max_retries": 3}
+ json_body, data_body = get_request_body(json=None, data=None, request_options=unrelated_request_options, omit=None)
+ assert json_body is None
+ assert data_body is None
+
+
+def test_explicit_empty_json_body_is_preserved() -> None:
+ """Test that explicit empty bodies (json={}) are preserved and sent as {}.
+
+ This is important for endpoints where the request body is required but all
+ fields are optional. The server expects valid JSON ({}) not an empty body.
+ """
+ unrelated_request_options: RequestOptions = {"max_retries": 3}
+
+ # Explicit json={} should be preserved
+ json_body, data_body = get_request_body(json={}, data=None, request_options=unrelated_request_options, omit=None)
+ assert json_body == {}
+ assert data_body is None
+
+ # Explicit data={} should also be preserved
+ json_body2, data_body2 = get_request_body(json=None, data={}, request_options=unrelated_request_options, omit=None)
+ assert json_body2 is None
+ assert data_body2 == {}
+
+
+def test_json_body_preserves_none_values() -> None:
+ """Test that JSON bodies preserve None values (they become JSON null)."""
+ json_body, data_body = get_request_body(
+ json={"hello": "world", "optional": None}, data=None, request_options=None, omit=None
+ )
+ # JSON bodies should preserve None values
+ assert json_body == {"hello": "world", "optional": None}
+ assert data_body is None
+
+
+def test_data_body_preserves_none_values_without_multipart() -> None:
+ """Test that data bodies preserve None values when not using multipart.
+
+ The filtering of None values happens in HttpClient.request/stream methods,
+ not in get_request_body. This test verifies get_request_body doesn't filter None.
+ """
+ json_body, data_body = get_request_body(
+ json=None, data={"hello": "world", "optional": None}, request_options=None, omit=None
+ )
+ # get_request_body should preserve None values in data body
+ # The filtering happens later in HttpClient.request when multipart is detected
+ assert data_body == {"hello": "world", "optional": None}
+ assert json_body is None
+
+
+def test_remove_none_from_dict_filters_none_values() -> None:
+ """Test that remove_none_from_dict correctly filters out None values."""
+ original = {"hello": "world", "optional": None, "another": "value", "also_none": None}
+ filtered = remove_none_from_dict(original)
+ assert filtered == {"hello": "world", "another": "value"}
+ # Original should not be modified
+ assert original == {"hello": "world", "optional": None, "another": "value", "also_none": None}
+
+
+def test_remove_none_from_dict_empty_dict() -> None:
+ """Test that remove_none_from_dict handles empty dict."""
+ assert remove_none_from_dict({}) == {}
+
+
+def test_remove_none_from_dict_all_none() -> None:
+ """Test that remove_none_from_dict handles dict with all None values."""
+ assert remove_none_from_dict({"a": None, "b": None}) == {}
+
+
+def test_http_client_does_not_pass_empty_params_list() -> None:
+ """Test that HttpClient passes params=None when params are empty.
+
+ This prevents httpx from stripping existing query parameters from the URL,
+ which happens when params=[] or params={} is passed.
+ """
+ dummy_client = _DummySyncClient()
+ http_client = HttpClient(
+ httpx_client=dummy_client, # type: ignore[arg-type]
+ base_timeout=lambda: None,
+ base_headers=lambda: {},
+ base_url=lambda: "https://example.com",
+ )
+
+ # Use a path with query params (e.g., pagination cursor URL)
+ http_client.request(
+ path="resource?after=123",
+ method="GET",
+ params=None,
+ request_options=None,
+ )
+
+ # We care that httpx receives params=None, not [] or {}
+ assert "params" in dummy_client.last_request_kwargs
+ assert dummy_client.last_request_kwargs["params"] is None
+
+ # Verify the query string in the URL is preserved
+ url = str(dummy_client.last_request_kwargs["url"])
+ assert "after=123" in url, f"Expected query param 'after=123' in URL, got: {url}"
+
+
+def test_http_client_passes_encoded_params_when_present() -> None:
+ """Test that HttpClient passes encoded params when params are provided."""
+ dummy_client = _DummySyncClient()
+ http_client = HttpClient(
+ httpx_client=dummy_client, # type: ignore[arg-type]
+ base_timeout=lambda: None,
+ base_headers=lambda: {},
+ base_url=lambda: "https://example.com/resource",
+ )
+
+ http_client.request(
+ path="",
+ method="GET",
+ params={"after": "456"},
+ request_options=None,
+ )
+
+ params = dummy_client.last_request_kwargs["params"]
+ # For a simple dict, encode_query should give a single (key, value) tuple
+ assert params == [("after", "456")]
+
+
+@pytest.mark.asyncio
+async def test_async_http_client_does_not_pass_empty_params_list() -> None:
+ """Test that AsyncHttpClient passes params=None when params are empty.
+
+ This prevents httpx from stripping existing query parameters from the URL,
+ which happens when params=[] or params={} is passed.
+ """
+ dummy_client = _DummyAsyncClient()
+ http_client = AsyncHttpClient(
+ httpx_client=dummy_client, # type: ignore[arg-type]
+ base_timeout=lambda: None,
+ base_headers=lambda: {},
+ base_url=lambda: "https://example.com",
+ async_base_headers=None,
+ )
+
+ # Use a path with query params (e.g., pagination cursor URL)
+ await http_client.request(
+ path="resource?after=123",
+ method="GET",
+ params=None,
+ request_options=None,
+ )
+
+ # We care that httpx receives params=None, not [] or {}
+ assert "params" in dummy_client.last_request_kwargs
+ assert dummy_client.last_request_kwargs["params"] is None
+
+ # Verify the query string in the URL is preserved
+ url = str(dummy_client.last_request_kwargs["url"])
+ assert "after=123" in url, f"Expected query param 'after=123' in URL, got: {url}"
+
+
+@pytest.mark.asyncio
+async def test_async_http_client_passes_encoded_params_when_present() -> None:
+ """Test that AsyncHttpClient passes encoded params when params are provided."""
+ dummy_client = _DummyAsyncClient()
+ http_client = AsyncHttpClient(
+ httpx_client=dummy_client, # type: ignore[arg-type]
+ base_timeout=lambda: None,
+ base_headers=lambda: {},
+ base_url=lambda: "https://example.com/resource",
+ async_base_headers=None,
+ )
+
+ await http_client.request(
+ path="",
+ method="GET",
+ params={"after": "456"},
+ request_options=None,
+ )
+
+ params = dummy_client.last_request_kwargs["params"]
+ # For a simple dict, encode_query should give a single (key, value) tuple
+ assert params == [("after", "456")]
+
+
+def test_basic_url_joining() -> None:
+ """Test basic URL joining with a simple base URL and path."""
+ result = _build_url("https://api.example.com", "/users")
+ assert result == "https://api.example.com/users"
+
+
+def test_basic_url_joining_trailing_slash() -> None:
+ """Test basic URL joining with a simple base URL and path."""
+ result = _build_url("https://api.example.com/", "/users")
+ assert result == "https://api.example.com/users"
+
+
+def test_preserves_base_url_path_prefix() -> None:
+ """Test that path prefixes in base URL are preserved.
+
+ This is the critical bug fix - urllib.parse.urljoin() would strip
+ the path prefix when the path starts with '/'.
+ """
+ result = _build_url("https://cloud.example.com/org/tenant/api", "/users")
+ assert result == "https://cloud.example.com/org/tenant/api/users"
+
+
+def test_preserves_base_url_path_prefix_trailing_slash() -> None:
+ """Test that path prefixes in base URL are preserved."""
+ result = _build_url("https://cloud.example.com/org/tenant/api/", "/users")
+ assert result == "https://cloud.example.com/org/tenant/api/users"
diff --git a/tests/utils/test_query_encoding.py b/tests/utils/test_query_encoding.py
new file mode 100644
index 0000000..c76b5d2
--- /dev/null
+++ b/tests/utils/test_query_encoding.py
@@ -0,0 +1,36 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from webflow.core.query_encoder import encode_query
+
+
+def test_query_encoding_deep_objects() -> None:
+ assert encode_query({"hello world": "hello world"}) == [("hello world", "hello world")]
+ assert encode_query({"hello_world": {"hello": "world"}}) == [("hello_world[hello]", "world")]
+ assert encode_query({"hello_world": {"hello": {"world": "today"}, "test": "this"}, "hi": "there"}) == [
+ ("hello_world[hello][world]", "today"),
+ ("hello_world[test]", "this"),
+ ("hi", "there"),
+ ]
+
+
+def test_query_encoding_deep_object_arrays() -> None:
+ assert encode_query({"objects": [{"key": "hello", "value": "world"}, {"key": "foo", "value": "bar"}]}) == [
+ ("objects[key]", "hello"),
+ ("objects[value]", "world"),
+ ("objects[key]", "foo"),
+ ("objects[value]", "bar"),
+ ]
+ assert encode_query(
+ {"users": [{"name": "string", "tags": ["string"]}, {"name": "string2", "tags": ["string2", "string3"]}]}
+ ) == [
+ ("users[name]", "string"),
+ ("users[tags]", "string"),
+ ("users[name]", "string2"),
+ ("users[tags]", "string2"),
+ ("users[tags]", "string3"),
+ ]
+
+
+def test_encode_query_with_none() -> None:
+ encoded = encode_query(None)
+ assert encoded is None
diff --git a/tests/utils/test_serialization.py b/tests/utils/test_serialization.py
new file mode 100644
index 0000000..af7b043
--- /dev/null
+++ b/tests/utils/test_serialization.py
@@ -0,0 +1,72 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from typing import Any, List
+
+from .assets.models import ObjectWithOptionalFieldParams, ShapeParams
+
+from webflow.core.serialization import convert_and_respect_annotation_metadata
+
+UNION_TEST: ShapeParams = {"radius_measurement": 1.0, "shape_type": "circle", "id": "1"}
+UNION_TEST_CONVERTED = {"shapeType": "circle", "radiusMeasurement": 1.0, "id": "1"}
+
+
+def test_convert_and_respect_annotation_metadata() -> None:
+ data: ObjectWithOptionalFieldParams = {
+ "string": "string",
+ "long_": 12345,
+ "bool_": True,
+ "literal": "lit_one",
+ "any": "any",
+ }
+ converted = convert_and_respect_annotation_metadata(
+ object_=data, annotation=ObjectWithOptionalFieldParams, direction="write"
+ )
+ assert converted == {"string": "string", "long": 12345, "bool": True, "literal": "lit_one", "any": "any"}
+
+
+def test_convert_and_respect_annotation_metadata_in_list() -> None:
+ data: List[ObjectWithOptionalFieldParams] = [
+ {"string": "string", "long_": 12345, "bool_": True, "literal": "lit_one", "any": "any"},
+ {"string": "another string", "long_": 67890, "list_": [], "literal": "lit_one", "any": "any"},
+ ]
+ converted = convert_and_respect_annotation_metadata(
+ object_=data, annotation=List[ObjectWithOptionalFieldParams], direction="write"
+ )
+
+ assert converted == [
+ {"string": "string", "long": 12345, "bool": True, "literal": "lit_one", "any": "any"},
+ {"string": "another string", "long": 67890, "list": [], "literal": "lit_one", "any": "any"},
+ ]
+
+
+def test_convert_and_respect_annotation_metadata_in_nested_object() -> None:
+ data: ObjectWithOptionalFieldParams = {
+ "string": "string",
+ "long_": 12345,
+ "union": UNION_TEST,
+ "literal": "lit_one",
+ "any": "any",
+ }
+ converted = convert_and_respect_annotation_metadata(
+ object_=data, annotation=ObjectWithOptionalFieldParams, direction="write"
+ )
+
+ assert converted == {
+ "string": "string",
+ "long": 12345,
+ "union": UNION_TEST_CONVERTED,
+ "literal": "lit_one",
+ "any": "any",
+ }
+
+
+def test_convert_and_respect_annotation_metadata_in_union() -> None:
+ converted = convert_and_respect_annotation_metadata(object_=UNION_TEST, annotation=ShapeParams, direction="write")
+
+ assert converted == UNION_TEST_CONVERTED
+
+
+def test_convert_and_respect_annotation_metadata_with_empty_object() -> None:
+ data: Any = {}
+ converted = convert_and_respect_annotation_metadata(object_=data, annotation=ShapeParams, direction="write")
+ assert converted == data