diff --git a/.fern/metadata.json b/.fern/metadata.json index b564d36..8e3e742 100644 --- a/.fern/metadata.json +++ b/.fern/metadata.json @@ -1,7 +1,7 @@ { "cliVersion": "5.50.0", "generatorName": "fernapi/fern-python-sdk", - "generatorVersion": "5.14.20", + "generatorVersion": "5.29.1", "generatorConfig": { "inline_request_params": true, "client": { @@ -23,10 +23,10 @@ } ] }, - "originGitCommit": "8cfe954dda14329fc30a4f80b915db0acf608382", + "originGitCommit": "008b7147a27272499bf4b17fa96d4357ca3b62e9", "originGitCommitIsDirty": false, "invokedBy": "ci", - "requestedVersion": "1.3.3", + "requestedVersion": "1.3.4", "ciProvider": "github", - "sdkVersion": "1.3.3" + "sdkVersion": "1.3.4" } \ No newline at end of file diff --git a/.fern/replay.lock b/.fern/replay.lock index ba9adcc..9cbd85c 100644 --- a/.fern/replay.lock +++ b/.fern/replay.lock @@ -36,5 +36,11 @@ generations: cli_version: unknown generator_versions: fernapi/fern-python-sdk: 5.14.20 -current_generation: 3bcc19082dd0caee045848158261be377bf337d5 + - commit_sha: e85d697e829ba85f2c9b84f3613717390fcc3bc0 + tree_hash: 59221ce98b55ba1dbd260238b8736fa736eff3ef + timestamp: 2026-08-24T10:14:22.169Z + cli_version: unknown + generator_versions: + fernapi/fern-python-sdk: 5.29.1 +current_generation: e85d697e829ba85f2c9b84f3613717390fcc3bc0 patches: [] diff --git a/poetry.lock b/poetry.lock index c1f782d..bd32c51 100644 --- a/poetry.lock +++ b/poetry.lock @@ -493,15 +493,15 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "httpx-aiohttp" -version = "0.1.8" +version = "0.1.12" description = "Aiohttp transport for HTTPX" optional = true python-versions = ">=3.8" groups = ["main"] markers = "extra == \"aiohttp\"" files = [ - {file = "httpx_aiohttp-0.1.8-py3-none-any.whl", hash = "sha256:b7bd958d1331f3759a38a0ba22ad29832cb63ca69498c17735228055bf78fa7e"}, - {file = "httpx_aiohttp-0.1.8.tar.gz", hash = "sha256:756c5e74cdb568c3248ba63fe82bfe8bbe64b928728720f7eaac64b3cf46f308"}, + {file = "httpx_aiohttp-0.1.12-py3-none-any.whl", hash = "sha256:5b0eac39a7f360fa7867a60bcb46bb1024eada9c01cbfecdb54dc1edb3fb7141"}, + {file = "httpx_aiohttp-0.1.12.tar.gz", hash = "sha256:81feec51fd82c0ecfa0e9aaf1b1a6c2591260d5e2bcbeb7eb0277a78e610df2c"}, ] [package.dependencies] @@ -510,18 +510,18 @@ httpx = ">=0.27.0" [[package]] name = "idna" -version = "3.18" +version = "3.19" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ - {file = "idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2"}, - {file = "idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848"}, + {file = "idna-3.19-py3-none-any.whl", hash = "sha256:815e7be7a7806d54abb586dc943addc79e8b2ee16915059658cbeff4b1b43bf4"}, + {file = "idna-3.19.tar.gz", hash = "sha256:5e0811a4383b21dc5838069f801c4fb62113b7447663d2530d2bd6e77b49bf15"}, ] [package.extras] -all = ["mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] +all = ["coverage (>=7.10.0)", "hypothesis (>=6.141.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.16.0)", "ty (>=0.0.37)"] [[package]] name = "iniconfig" @@ -1316,14 +1316,14 @@ files = [ [[package]] name = "typing-inspection" -version = "0.4.3" +version = "0.4.4" description = "Runtime typing introspection tools" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "typing_inspection-0.4.3-py3-none-any.whl", hash = "sha256:5f42b23858a91e0b4ef521f5418f03a0da3c9216fd2995ef5e73463100e676cd"}, - {file = "typing_inspection-0.4.3.tar.gz", hash = "sha256:c5f9ec1530b5c1e2c9bc34a84d9a3466ed1b2f3f2fa9f901368d9c5596210e4d"}, + {file = "typing_inspection-0.4.4-py3-none-any.whl", hash = "sha256:65b8397ba37ccbce054456aaccddfc91e6e3083c92824df348d96ca832f3f147"}, + {file = "typing_inspection-0.4.4.tar.gz", hash = "sha256:547274fa6b0a561ccf549cc9524b999a578e737d015d8709d021f9d0d13bea47"}, ] [package.dependencies] @@ -1331,25 +1331,25 @@ typing-extensions = ">=4.15.0" [[package]] name = "wasmtime" -version = "47.0.1" +version = "48.0.0" description = "A WebAssembly runtime powered by Wasmtime" optional = true python-versions = ">=3.9" groups = ["main"] markers = "extra == \"datastream\" or extra == \"rulesengine\"" files = [ - {file = "wasmtime-47.0.1-py3-none-android_26_arm64_v8a.whl", hash = "sha256:844d85628e50929143f03af9a34b3cf5c9148747debced80c14776d27e18173c"}, - {file = "wasmtime-47.0.1-py3-none-android_26_x86_64.whl", hash = "sha256:749c5c1271ca208f1026001ddc65984fa98113e583521d47ae7e11bc96bf337d"}, - {file = "wasmtime-47.0.1-py3-none-any.whl", hash = "sha256:5146a700c93909e797e0f6c05707c992fc75f4f5f5c5ecf826a9aff689ec6af1"}, - {file = "wasmtime-47.0.1-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:8b4ec103273ec3dce86efe6793d41f83df713983d9cbc5c9662adbb56cf00ffe"}, - {file = "wasmtime-47.0.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:58da69f71750e844e32614c1805246ffca4c8b032d46a8145faa26c228c6c5ac"}, - {file = "wasmtime-47.0.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:9724600b036c6e95c4fe952e29fad83b4f02bdc11d23f25c4ee3ffff2c1d7257"}, - {file = "wasmtime-47.0.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:4f72162ceed1d50de8226fac6b12e1ecce54883a0c3f7355bb141eae40df488a"}, - {file = "wasmtime-47.0.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0aeb53d4c8e682cccebbaac48882939b34e71a1243b622129de3e6834728044d"}, - {file = "wasmtime-47.0.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:f900fa571a9a5668b6210de9ecca1c5b66db14d85b7c36514c3d307d4f4cdc90"}, - {file = "wasmtime-47.0.1-py3-none-win_amd64.whl", hash = "sha256:4e46a4a29092a2ac1001159d5673e2a23996f4474261c791401867b1630429f4"}, - {file = "wasmtime-47.0.1-py3-none-win_arm64.whl", hash = "sha256:812058e7b40b73defa1d5118c25faa674920b7833c0a22cf79f0ff4eadee0c32"}, - {file = "wasmtime-47.0.1.tar.gz", hash = "sha256:fab6ee0e87354f14ef228fa71b40841dd3c2c713f6efce636af234b4e3e6edcc"}, + {file = "wasmtime-48.0.0-py3-none-android_26_arm64_v8a.whl", hash = "sha256:a55abf132fe238b843a963c68cd1a30d8f686c1bc75d8fbf042d8b7a1d51ee36"}, + {file = "wasmtime-48.0.0-py3-none-android_26_x86_64.whl", hash = "sha256:d8e94276ff6c0c5ce73ee16ccbacb00b3512a4b3a664749380705d81ee06a23c"}, + {file = "wasmtime-48.0.0-py3-none-any.whl", hash = "sha256:49c9ee43e9cf59ad7453ac65dce0cc4b885837904dd3cfd45faafe930defe14a"}, + {file = "wasmtime-48.0.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:50e1ea81a3bec537d00e076722dfdc48978a56ea24619d8153aa1f75b11796b9"}, + {file = "wasmtime-48.0.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:ea69889a3c51702e9da5f5f441027ca934f7758f8926a4ed167b0d6877f092e8"}, + {file = "wasmtime-48.0.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:58544d539053dff7bd4cf30c40d7a540862d683013c0dfa6ba46a063f5b682f7"}, + {file = "wasmtime-48.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:26fce3613fefbe29a28e9d659dca3326e800593858e5758cad086eb802b3b766"}, + {file = "wasmtime-48.0.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:77f6b75db20be065e205e7af814d4e4f06784c3a00eb346e8c76148ecb4afe5a"}, + {file = "wasmtime-48.0.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:62b241c8d5dfb59ff8af1ccaa5351f0ab7aba8cc872f7d80e0e3c95d54c13562"}, + {file = "wasmtime-48.0.0-py3-none-win_amd64.whl", hash = "sha256:21fa500e70f3819a8c0539c3f0be6b3b81ec3c630bb90c47dba4d8a2c1d4c698"}, + {file = "wasmtime-48.0.0-py3-none-win_arm64.whl", hash = "sha256:09cd5e14df80a3a8d447428a548583181c568ea2e617419d23600deff21d4b82"}, + {file = "wasmtime-48.0.0.tar.gz", hash = "sha256:dba27d59209fac703e7d5753af78c2af2c1cd1ed735f520ec76dc31c60a05815"}, ] [package.extras] diff --git a/pyproject.toml b/pyproject.toml index 1102244..ab92619 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ dynamic = ["version"] [tool.poetry] name = "schematichq" -version = "1.3.3" +version = "1.3.4" description = "" readme = "README.md" authors = [] diff --git a/reference.md b/reference.md index 375ec45..4f48ef7 100644 --- a/reference.md +++ b/reference.md @@ -1389,6 +1389,136 @@ client.accounts.delete_environment( + + + + +
client.accounts.get_onboarding_state() -> GetOnboardingStateResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from schematic import Schematic +from schematic.environment import SchematicEnvironment + +client = Schematic( + api_key="", + environment=SchematicEnvironment.DEFAULT, +) + +client.accounts.get_onboarding_state() + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.accounts.update_onboarding_state(...) -> UpdateOnboardingStateResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from schematic import Schematic +from schematic.environment import SchematicEnvironment + +client = Schematic( + api_key="", + environment=SchematicEnvironment.DEFAULT, +) + +client.accounts.update_onboarding_state() + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**path:** `typing.Optional[OnboardingPath]` + +
+
+ +
+
+ +**pricing_page_url:** `typing.Optional[str]` + +
+
+ +
+
+ +**track:** `typing.Optional[OnboardingTrack]` + +
+
+ +
+
+ +**website_url:** `typing.Optional[str]` + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ +
@@ -5138,6 +5268,14 @@ client.credits.create_credit_bundle(
+**compatible_plan_ids:** `typing.Optional[typing.List[str]]` — Plans whose companies may purchase this bundle. Omitted or empty means the bundle is purchasable on every plan. + +
+
+ +
+
+ **currency_prices:** `typing.Optional[typing.List[CreditBundleCurrencyPriceRequestBody]]`
@@ -5330,6 +5468,14 @@ client.credits.update_credit_bundle_details(
+**compatible_plan_ids:** `typing.Optional[typing.List[str]]` — Plans whose companies may purchase this bundle. Omitted leaves compatibility unchanged; empty resets the bundle to purchasable on every plan. + +
+
+ +
+
+ **currency_prices:** `typing.Optional[typing.List[CreditBundleCurrencyPriceRequestBody]]`
@@ -5911,7 +6057,7 @@ client.credits.count_company_grants(
-**company_id:** `typing.Optional[str]` +**company_id:** `str`
@@ -6006,7 +6152,7 @@ client.credits.list_company_grants(
-**company_id:** `typing.Optional[str]` +**company_id:** `str`
@@ -8985,6 +9131,7 @@ client.companies.list_companies( plan_version_ids=[ "plan_version_ids" ], + plan_version_unpublished=True, q="q", sort_order_column="sort_order_column", sort_order_direction="asc", @@ -9081,6 +9228,14 @@ client.companies.list_companies(
+**plan_version_unpublished:** `typing.Optional[bool]` — Filter companies assigned to a plan version that is no longer published, meaning the plan has since moved on to a newer version + +
+
+ +
+
+ **q:** `typing.Optional[str]` — Search for companies by name, keys or string traits
@@ -9424,6 +9579,7 @@ client.companies.count_companies( plan_version_ids=[ "plan_version_ids" ], + plan_version_unpublished=True, q="q", sort_order_column="sort_order_column", sort_order_direction="asc", @@ -9520,6 +9676,14 @@ client.companies.count_companies(
+**plan_version_unpublished:** `typing.Optional[bool]` — Filter companies assigned to a plan version that is no longer published, meaning the plan has since moved on to a newer version + +
+
+ +
+
+ **q:** `typing.Optional[str]` — Search for companies by name, keys or string traits
@@ -9868,7 +10032,7 @@ client.companies.get_company_billing_entity(
-**company_id:** `typing.Optional[str]` +**company_id:** `str`
@@ -9927,7 +10091,7 @@ client.companies.get_billing_entity_child_subscriptions(
-**company_id:** `typing.Optional[str]` +**company_id:** `str`
@@ -10984,6 +11148,124 @@ client.companies.update_entity_trait_definition(
+ +
+ + +
client.companies.delete_entity_trait_definition(...) -> DeleteEntityTraitDefinitionResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from schematic import Schematic +from schematic.environment import SchematicEnvironment + +client = Schematic( + api_key="", + environment=SchematicEnvironment.DEFAULT, +) + +client.companies.delete_entity_trait_definition( + entity_trait_definition_id="entity_trait_definition_id", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**entity_trait_definition_id:** `str` — entity_trait_definition_id + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.companies.get_entity_trait_definition_usage(...) -> GetEntityTraitDefinitionUsageResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from schematic import Schematic +from schematic.environment import SchematicEnvironment + +client = Schematic( + api_key="", + environment=SchematicEnvironment.DEFAULT, +) + +client.companies.get_entity_trait_definition_usage( + entity_trait_definition_id="entity_trait_definition_id", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**entity_trait_definition_id:** `str` — entity_trait_definition_id + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ +
@@ -11187,6 +11469,92 @@ client.companies.get_entity_trait_values(
+ +
+ + +
client.companies.count_entity_traits(...) -> CountEntityTraitsResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from schematic import Schematic +from schematic.environment import SchematicEnvironment + +client = Schematic( + api_key="", + environment=SchematicEnvironment.DEFAULT, +) + +client.companies.count_entity_traits( + definition_id="definition_id", + entity_type="company", + limit=1000000, + offset=1000000, +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**definition_id:** `typing.Optional[str]` + +
+
+ +
+
+ +**entity_type:** `typing.Optional[EntityType]` + +
+
+ +
+
+ +**limit:** `typing.Optional[int]` — Page limit (default 100) + +
+
+ +
+
+ +**offset:** `typing.Optional[int]` — Page offset (default 0) + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ +
@@ -11219,9 +11587,6 @@ client.companies.list_plan_changes( company_ids=[ "company_ids" ], - plan_ids=[ - "plan_ids" - ], limit=1000000, offset=1000000, ) @@ -11272,14 +11637,6 @@ client.companies.list_plan_changes(
-**plan_ids:** `typing.Optional[typing.Union[str, typing.Sequence[str]]]` - -
-
- -
-
- **limit:** `typing.Optional[int]` — Page limit (default 100)
@@ -13342,6 +13699,124 @@ client.entitlements.list_feature_usage(
+ + + + +
client.entitlements.list_feature_usage_history(...) -> ListFeatureUsageHistoryResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from schematic import Schematic +from schematic.environment import SchematicEnvironment +import datetime + +client = Schematic( + api_key="", + environment=SchematicEnvironment.DEFAULT, +) + +client.entitlements.list_feature_usage_history( + company_ids=[ + "company_ids" + ], + end_time=datetime.datetime.fromisoformat("2024-01-15T09:30:00+00:00"), + feature_ids=[ + "feature_ids" + ], + granularity="daily", + start_time=datetime.datetime.fromisoformat("2024-01-15T09:30:00+00:00"), + limit=1000000, + offset=1000000, +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**end_time:** `datetime.datetime` — Exclusive end of the window; must fall on an hour boundary + +
+
+ +
+
+ +**start_time:** `datetime.datetime` — Inclusive start of the window; must fall on an hour boundary + +
+
+ +
+
+ +**company_ids:** `typing.Optional[typing.Union[str, typing.Sequence[str]]]` — Restrict to these company IDs; omit for every company in the environment + +
+
+ +
+
+ +**feature_ids:** `typing.Optional[typing.Union[str, typing.Sequence[str]]]` — Restrict to these event features; omit for every event feature in the environment. Where several features measure the same event, each is reported separately and a page may carry more rows than the requested limit + +
+
+ +
+
+ +**granularity:** `typing.Optional[TimeSeriesGranularity]` — Bucket the window; omit for a single total per company and feature + +
+
+ +
+
+ +**limit:** `typing.Optional[int]` — Page limit (default 100) + +
+
+ +
+
+ +**offset:** `typing.Optional[int]` — Page offset (default 0) + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ +
@@ -15480,7 +15955,7 @@ client = Schematic( ) client.plans.update_company_plans( - company_plan_id="company_plan_id", + company_id="company_id", add_on_ids=[ "add_on_ids" ], @@ -15500,7 +15975,7 @@ client.plans.update_company_plans(
-**company_plan_id:** `str` — company_plan_id +**company_id:** `str` — company_id
@@ -15560,6 +16035,7 @@ client = Schematic( client.plans.list_custom_plan_billings( company_id="company_id", plan_id="plan_id", + plan_billing_source="custom_plan", status="active", statuses=[ "active" @@ -15598,6 +16074,14 @@ client.plans.list_custom_plan_billings(
+**plan_billing_source:** `typing.Optional[PlanBillingSource]` — Filter by the flow that created the billing record. Defaults to custom_plan. + +
+
+ +
+
+ **status:** `typing.Optional[CustomPlanBillingStatus]` — Filter by billing status
@@ -15827,7 +16311,6 @@ client = Schematic( client.plans.create_custom_plan( company_id="company_id", - description="description", name="name", ) @@ -15853,7 +16336,7 @@ client.plans.create_custom_plan(
-**description:** `str` +**name:** `str`
@@ -15861,7 +16344,7 @@ client.plans.create_custom_plan(
-**name:** `str` +**copied_from_plan_id:** `typing.Optional[str]`
@@ -15869,7 +16352,15 @@ client.plans.create_custom_plan(
-**copied_from_plan_id:** `typing.Optional[str]` +**copied_price_id:** `typing.Optional[str]` + +
+
+ +
+
+ +**description:** `typing.Optional[str]`
@@ -16124,7 +16615,6 @@ client = Schematic( ) client.plans.create_plan( - description="description", name="name", plan_type="plan", ) @@ -16450,7 +16940,6 @@ client = Schematic( client.plans.upsert_plan_for_billing_product( billing_provider="metronome", - description="description", external_resource_id="external_resource_id", name="name", plan_type="plan", @@ -16478,7 +16967,7 @@ client.plans.upsert_plan_for_billing_product(
-**description:** `str` +**external_resource_id:** `str`
@@ -16486,7 +16975,7 @@ client.plans.upsert_plan_for_billing_product(
-**external_resource_id:** `str` +**name:** `str`
@@ -16494,7 +16983,7 @@ client.plans.upsert_plan_for_billing_product(
-**name:** `str` +**plan_type:** `PlanType`
@@ -16502,7 +16991,7 @@ client.plans.upsert_plan_for_billing_product(
-**plan_type:** `PlanType` +**description:** `typing.Optional[str]`
@@ -17005,7 +17494,7 @@ client = Schematic( ) client.plans.delete_plan_version( - plan_id="plan_id", + plan_version_id="plan_version_id", promote_archived_version=True, ) @@ -17023,7 +17512,7 @@ client.plans.delete_plan_version(
-**plan_id:** `str` — plan_id +**plan_version_id:** `str` — plan_version_id
@@ -17073,7 +17562,7 @@ client = Schematic( ) client.plans.publish_plan_version( - plan_id="plan_id", + plan_version_id="plan_version_id", excluded_company_ids=[ "excluded_company_ids" ], @@ -17094,7 +17583,7 @@ client.plans.publish_plan_version(
-**plan_id:** `str` — plan_id +**plan_version_id:** `str` — plan_version_id
@@ -17174,6 +17663,22 @@ client.plans.publish_plan_version(
+**proration_behavior:** `typing.Optional[MigrationProrationBehavior]` + +
+
+ +
+
+ +**require_no_migration:** `typing.Optional[bool]` — Refuse the publish if any company would be migrated onto the new version + +
+
+ +
+
+ **send_invoice:** `typing.Optional[bool]` — Whether Stripe emails the invoice when it is finalized. Defaults to true.
@@ -17791,7 +18296,7 @@ client.components.preview_component_data(
```python -from schematic import Schematic, PlanBundleEntitlementRequestBody +from schematic import Schematic, UpsertBillingProductRequestBody, PlanBundleEntitlementRequestBody, CreateCustomPlanBundlePlanRequestBody from schematic.environment import SchematicEnvironment client = Schematic( @@ -17800,11 +18305,19 @@ client = Schematic( ) client.planbundle.create_custom_plan_bundle( + billing_product=UpsertBillingProductRequestBody( + charge_type="free", + is_trialable=True, + ), entitlements=[ PlanBundleEntitlementRequestBody( action="create", ) ], + plan=CreateCustomPlanBundlePlanRequestBody( + company_id="company_id", + name="name", + ), ) ``` @@ -17821,7 +18334,7 @@ client.planbundle.create_custom_plan_bundle(
-**entitlements:** `typing.List[PlanBundleEntitlementRequestBody]` +**billing_product:** `UpsertBillingProductRequestBody`
@@ -17829,7 +18342,7 @@ client.planbundle.create_custom_plan_bundle(
-**billing_product:** `typing.Optional[UpsertBillingProductRequestBody]` +**entitlements:** `typing.List[PlanBundleEntitlementRequestBody]`
@@ -17837,7 +18350,7 @@ client.planbundle.create_custom_plan_bundle(
-**credit_grants:** `typing.Optional[typing.List[PlanBundleCreditGrantRequestBody]]` +**plan:** `CreateCustomPlanBundlePlanRequestBody`
@@ -17845,7 +18358,7 @@ client.planbundle.create_custom_plan_bundle(
-**plan:** `typing.Optional[CreateCustomPlanBundlePlanRequestBody]` +**credit_grants:** `typing.Optional[typing.List[PlanBundleCreditGrantRequestBody]]`
@@ -17878,7 +18391,7 @@ client.planbundle.create_custom_plan_bundle(
```python -from schematic import Schematic, PlanBundleEntitlementRequestBody +from schematic import Schematic, PlanBundleEntitlementRequestBody, CreatePlanRequestBody from schematic.environment import SchematicEnvironment client = Schematic( @@ -17892,6 +18405,10 @@ client.planbundle.create_plan_bundle( action="create", ) ], + plan=CreatePlanRequestBody( + name="name", + plan_type="plan", + ), ) ``` @@ -17916,7 +18433,7 @@ client.planbundle.create_plan_bundle(
-**billing_product:** `typing.Optional[UpsertBillingProductRequestBody]` +**plan:** `CreatePlanRequestBody`
@@ -17924,7 +18441,7 @@ client.planbundle.create_plan_bundle(
-**credit_grants:** `typing.Optional[typing.List[PlanBundleCreditGrantRequestBody]]` +**billing_product:** `typing.Optional[UpsertBillingProductRequestBody]`
@@ -17932,7 +18449,7 @@ client.planbundle.create_plan_bundle(
-**plan:** `typing.Optional[CreatePlanRequestBody]` +**credit_grants:** `typing.Optional[typing.List[PlanBundleCreditGrantRequestBody]]`
@@ -17965,7 +18482,7 @@ client.planbundle.create_plan_bundle(
```python -from schematic import Schematic, PlanBundleEntitlementRequestBody +from schematic import Schematic, PlanBundleEntitlementRequestBody, UpdatePlanRequestBody from schematic.environment import SchematicEnvironment client = Schematic( @@ -17974,12 +18491,15 @@ client = Schematic( ) client.planbundle.update_plan_bundle( - plan_bundle_id="plan_bundle_id", + plan_id="plan_id", entitlements=[ PlanBundleEntitlementRequestBody( action="create", ) ], + plan=UpdatePlanRequestBody( + name="name", + ), ) ``` @@ -17996,7 +18516,7 @@ client.planbundle.update_plan_bundle(
-**plan_bundle_id:** `str` — plan_bundle_id +**plan_id:** `str` — plan_id
@@ -18012,7 +18532,7 @@ client.planbundle.update_plan_bundle(
-**billing_product:** `typing.Optional[UpsertBillingProductRequestBody]` +**plan:** `UpdatePlanRequestBody`
@@ -18020,7 +18540,7 @@ client.planbundle.update_plan_bundle(
-**credit_grants:** `typing.Optional[typing.List[PlanBundleCreditGrantRequestBody]]` +**billing_product:** `typing.Optional[UpsertBillingProductRequestBody]`
@@ -18028,7 +18548,7 @@ client.planbundle.update_plan_bundle(
-**plan:** `typing.Optional[UpdatePlanRequestBody]` +**credit_grants:** `typing.Optional[typing.List[PlanBundleCreditGrantRequestBody]]`
@@ -21720,6 +22240,7 @@ client.plangroups.create_plan_group( checkout_collect_address=True, checkout_collect_email=True, checkout_collect_phone=True, + checkout_collect_tax_id=True, enable_tax_collection=True, opt_in_enabled=True, ordered_add_ons=[ @@ -21795,6 +22316,14 @@ client.plangroups.create_plan_group(
+**checkout_collect_tax_id:** `bool` + +
+
+ +
+
+ **enable_tax_collection:** `bool`
@@ -21923,6 +22452,14 @@ client.plangroups.create_plan_group(
+**checkout_bundle_purchase_behavior:** `typing.Optional[CheckoutBundlePurchaseBehavior]` + +
+
+ +
+
+ **custom_checkout_fields:** `typing.Optional[typing.List[CheckoutFieldInput]]`
@@ -22092,6 +22629,7 @@ client.plangroups.update_plan_group( checkout_collect_address=True, checkout_collect_email=True, checkout_collect_phone=True, + checkout_collect_tax_id=True, enable_tax_collection=True, opt_in_enabled=True, ordered_add_ons=[ @@ -22175,6 +22713,14 @@ client.plangroups.update_plan_group(
+**checkout_collect_tax_id:** `bool` + +
+
+ +
+
+ **enable_tax_collection:** `bool`
@@ -22303,6 +22849,14 @@ client.plangroups.update_plan_group(
+**checkout_bundle_purchase_behavior:** `typing.Optional[CheckoutBundlePurchaseBehavior]` + +
+
+ +
+
+ **custom_checkout_fields:** `typing.Optional[typing.List[CheckoutFieldInput]]`
@@ -22487,7 +23041,7 @@ client.planmigrations.list_company_migrations(
-**migration_id:** `typing.Optional[str]` +**migration_id:** `str`
@@ -22641,7 +23195,7 @@ client.planmigrations.count_company_migrations(
-**migration_id:** `typing.Optional[str]` +**migration_id:** `str`
@@ -22735,7 +23289,7 @@ client.planmigrations.list_migrations(
-**plan_version_id:** `typing.Optional[str]` +**plan_version_id:** `str`
@@ -22801,17 +23355,8 @@ client = Schematic( ) client.planmigrations.create_migration( - company_ids=[ - "company_ids" - ], - excluded_company_ids=[ - "excluded_company_ids" - ], plan_id="plan_id", plan_version_id_to="plan_version_id_to", - plan_version_ids_from=[ - "plan_version_ids_from" - ], strategy="immediate", target_plan_type="plan", ) @@ -22830,7 +23375,15 @@ client.planmigrations.create_migration(
-**company_ids:** `typing.List[str]` +**plan_id:** `str` + +
+
+ +
+
+ +**plan_version_id_to:** `str`
@@ -22838,7 +23391,7 @@ client.planmigrations.create_migration(
-**excluded_company_ids:** `typing.List[str]` +**strategy:** `PlanVersionMigrationStrategy`
@@ -22846,7 +23399,7 @@ client.planmigrations.create_migration(
-**plan_id:** `str` +**target_plan_type:** `PlanType`
@@ -22854,7 +23407,7 @@ client.planmigrations.create_migration(
-**plan_version_id_to:** `str` +**company_ids:** `typing.Optional[typing.List[str]]`
@@ -22862,7 +23415,7 @@ client.planmigrations.create_migration(
-**plan_version_ids_from:** `typing.List[str]` +**excluded_company_ids:** `typing.Optional[typing.List[str]]`
@@ -22870,7 +23423,7 @@ client.planmigrations.create_migration(
-**strategy:** `PlanVersionMigrationStrategy` +**plan_version_ids_from:** `typing.Optional[typing.List[str]]`
@@ -22878,7 +23431,7 @@ client.planmigrations.create_migration(
-**target_plan_type:** `PlanType` +**proration_behavior:** `typing.Optional[MigrationProrationBehavior]`
@@ -23069,7 +23622,7 @@ client.planmigrations.count_migrations(
-**plan_version_id:** `typing.Optional[str]` +**plan_version_id:** `str`
@@ -23135,9 +23688,6 @@ client = Schematic( ) client.planmigrations.preview_migration( - company_ids=[ - "company_ids" - ], plan_id="plan_id", plan_version_id_to="plan_version_id_to", target_plan_type="plan", @@ -23157,7 +23707,7 @@ client.planmigrations.preview_migration(
-**company_ids:** `typing.List[str]` +**plan_id:** `str`
@@ -23165,7 +23715,7 @@ client.planmigrations.preview_migration(
-**plan_id:** `str` +**plan_version_id_to:** `str`
@@ -23173,7 +23723,7 @@ client.planmigrations.preview_migration(
-**plan_version_id_to:** `str` +**target_plan_type:** `PlanType`
@@ -23181,7 +23731,15 @@ client.planmigrations.preview_migration(
-**target_plan_type:** `PlanType` +**company_ids:** `typing.Optional[typing.List[str]]` + +
+
+ +
+
+ +**plan_version_ids_from:** `typing.Optional[typing.List[str]]`
diff --git a/src/schematic/__init__.py b/src/schematic/__init__.py index a5c459d..ccc2e26 100644 --- a/src/schematic/__init__.py +++ b/src/schematic/__init__.py @@ -21,6 +21,7 @@ AuditLogExportMetadata, AuditLogListResponseData, AuditLogResponseData, + BillingCollectionMethod, BillingCouponResponseData, BillingCreditAutoTopupAvailability, BillingCreditBundleResponseData, @@ -89,6 +90,7 @@ CheckFlagResponseData, CheckFlagsBulkResponseData, CheckFlagsResponseData, + CheckoutBundlePurchaseBehavior, CheckoutDataResponseData, CheckoutFieldInput, CheckoutFieldResponseData, @@ -216,6 +218,7 @@ EntityKeyDetailResponseData, EntityKeyResponseData, EntityTraitDefinitionResponseData, + EntityTraitDefinitionUsage, EntityTraitDetailResponseData, EntityTraitResponseData, EntityTraitValue, @@ -249,6 +252,7 @@ FeatureResponseData, FeatureType, FeatureUsageDetailResponseData, + FeatureUsageHistoryResponseData, FeatureUsageLegacyResponseData, FeatureUsageResponseData, FeatureUsageTimeSeriesResponseData, @@ -259,6 +263,7 @@ FlagType, FlagView, GenericPreviewObject, + GetOnboardingStateResp, InsightsSummaryResponseData, InstallIntegrationRequestBody, IntegrationCapabilities, @@ -293,11 +298,20 @@ MetricPeriodMonthReset, MetronomeIntegrationConfig, MigrationErrorCode, + MigrationProrationBehavior, MrrResponseData, + OnboardingMilestone, + OnboardingMilestoneView, + OnboardingPath, + OnboardingRequirement, + OnboardingRequirementStatus, + OnboardingRequirementView, + OnboardingTrack, OrbIntegrationConfig, OrderedPlansInGroup, PaymentMethodRequestBody, PaymentMethodResponseData, + PlanBillingSource, PlanBundleAction, PlanBundleCreditGrantRequestBody, PlanBundleEntitlementRequestBody, @@ -340,6 +354,8 @@ PlanVersionSnapshotView, PlanVersionStatus, PlanViewPublicResponseData, + PreflightEventUsageRequestBody, + PreflightRequestBody, PreviewObject, PreviewObjectResponseData, PreviewSubscriptionChangeResponseData, @@ -408,6 +424,7 @@ TraitDefinitionComparableType, TraitType, TrialStatus, + UpcomingInvoiceResponseData, UpdateAddOnRequestBody, UpdateAutoTopupOverrideRequestBody, UpdateBillingPlanCreditGrantRequestBody, @@ -490,6 +507,7 @@ GetApiKeyResponse, GetAuditLogResponse, GetEnvironmentResponse, + GetOnboardingStateResponse, GetWhoAmIResponse, ListAccountMembersParams, ListAccountMembersResponse, @@ -502,6 +520,7 @@ QuickstartResponse, UpdateApiKeyResponse, UpdateEnvironmentResponse, + UpdateOnboardingStateResponse, ) from .billing import ( CountBillingProductsParams, @@ -573,6 +592,8 @@ CountEntityKeysResponse, CountEntityTraitDefinitionsParams, CountEntityTraitDefinitionsResponse, + CountEntityTraitsParams, + CountEntityTraitsResponse, CountPlanTraitsParams, CountPlanTraitsResponse, CountUsersParams, @@ -584,6 +605,7 @@ DeleteCompanyParams, DeleteCompanyResponse, DeleteEntityKeyDefinitionResponse, + DeleteEntityTraitDefinitionResponse, DeleteUserByKeysResponse, DeleteUserResponse, GetActiveCompanySubscriptionParams, @@ -594,6 +616,7 @@ GetCompanyBillingEntityResponse, GetCompanyResponse, GetEntityTraitDefinitionResponse, + GetEntityTraitDefinitionUsageResponse, GetEntityTraitValuesParams, GetEntityTraitValuesResponse, GetOrCreateCompanyMembershipResponse, @@ -722,6 +745,8 @@ ListCompanyOverridesResponse, ListFeatureCompaniesParams, ListFeatureCompaniesResponse, + ListFeatureUsageHistoryParams, + ListFeatureUsageHistoryResponse, ListFeatureUsageParams, ListFeatureUsageResponse, ListFeatureUsersParams, @@ -887,6 +912,7 @@ "AuditLogListResponseData": ".types", "AuditLogResponseData": ".types", "BadRequestError": ".errors", + "BillingCollectionMethod": ".types", "BillingCouponResponseData": ".types", "BillingCreditAutoTopupAvailability": ".types", "BillingCreditBundleResponseData": ".types", @@ -960,6 +986,7 @@ "CheckFlagsBulkResponseData": ".types", "CheckFlagsResponse": ".features", "CheckFlagsResponseData": ".types", + "CheckoutBundlePurchaseBehavior": ".types", "CheckoutDataResponseData": ".types", "CheckoutFieldInput": ".types", "CheckoutFieldResponseData": ".types", @@ -1052,6 +1079,8 @@ "CountEntityKeysResponse": ".companies", "CountEntityTraitDefinitionsParams": ".companies", "CountEntityTraitDefinitionsResponse": ".companies", + "CountEntityTraitsParams": ".companies", + "CountEntityTraitsResponse": ".companies", "CountFeatureCompaniesParams": ".entitlements", "CountFeatureCompaniesResponse": ".entitlements", "CountFeatureUsageParams": ".entitlements", @@ -1182,6 +1211,7 @@ "DeleteComponentResponse": ".components", "DeleteCreditBundleResponse": ".credits", "DeleteEntityKeyDefinitionResponse": ".companies", + "DeleteEntityTraitDefinitionResponse": ".companies", "DeleteEnvironmentResponse": ".accounts", "DeleteFeatureResponse": ".features", "DeleteFlagResponse": ".features", @@ -1207,6 +1237,7 @@ "EntityKeyDetailResponseData": ".types", "EntityKeyResponseData": ".types", "EntityTraitDefinitionResponseData": ".types", + "EntityTraitDefinitionUsage": ".types", "EntityTraitDetailResponseData": ".types", "EntityTraitResponseData": ".types", "EntityTraitValue": ".types", @@ -1241,6 +1272,7 @@ "FeatureResponseData": ".types", "FeatureType": ".types", "FeatureUsageDetailResponseData": ".types", + "FeatureUsageHistoryResponseData": ".types", "FeatureUsageLegacyResponseData": ".types", "FeatureUsageResponseData": ".types", "FeatureUsageTimeSeriesResponseData": ".types", @@ -1275,6 +1307,7 @@ "GetDataExportResponse": ".dataexports", "GetDerivedFeaturesResponse": ".catalogs", "GetEntityTraitDefinitionResponse": ".companies", + "GetEntityTraitDefinitionUsageResponse": ".companies", "GetEntityTraitValuesParams": ".companies", "GetEntityTraitValuesResponse": ".companies", "GetEnvironmentFeatureUsageTimeSeriesParams": ".insights", @@ -1293,6 +1326,8 @@ "GetFlagResponse": ".features", "GetIntegrationWebhookUrlResponse": ".integrationsapi", "GetMigrationResponse": ".planmigrations", + "GetOnboardingStateResp": ".types", + "GetOnboardingStateResponse": ".accounts", "GetOrCreateCompanyMembershipResponse": ".companies", "GetOrCreateEntityTraitDefinitionResponse": ".companies", "GetPlanChangeResponse": ".companies", @@ -1408,6 +1443,8 @@ "ListEventsResponse": ".events", "ListFeatureCompaniesParams": ".entitlements", "ListFeatureCompaniesResponse": ".entitlements", + "ListFeatureUsageHistoryParams": ".entitlements", + "ListFeatureUsageHistoryResponse": ".entitlements", "ListFeatureUsageParams": ".entitlements", "ListFeatureUsageResponse": ".entitlements", "ListFeatureUsersParams": ".entitlements", @@ -1465,12 +1502,21 @@ "MetricPeriodMonthReset": ".types", "MetronomeIntegrationConfig": ".types", "MigrationErrorCode": ".types", + "MigrationProrationBehavior": ".types", "MrrResponseData": ".types", "NotFoundError": ".errors", + "OnboardingMilestone": ".types", + "OnboardingMilestoneView": ".types", + "OnboardingPath": ".types", + "OnboardingRequirement": ".types", + "OnboardingRequirementStatus": ".types", + "OnboardingRequirementView": ".types", + "OnboardingTrack": ".types", "OrbIntegrationConfig": ".types", "OrderedPlansInGroup": ".types", "PaymentMethodRequestBody": ".types", "PaymentMethodResponseData": ".types", + "PlanBillingSource": ".types", "PlanBundleAction": ".types", "PlanBundleCreditGrantRequestBody": ".types", "PlanBundleEntitlementRequestBody": ".types", @@ -1513,6 +1559,8 @@ "PlanVersionSnapshotView": ".types", "PlanVersionStatus": ".types", "PlanViewPublicResponseData": ".types", + "PreflightEventUsageRequestBody": ".types", + "PreflightRequestBody": ".types", "PreviewCheckoutInternalResponse": ".checkout", "PreviewComponentDataParams": ".components", "PreviewComponentDataResponse": ".components", @@ -1601,6 +1649,7 @@ "TrialStatus": ".types", "UnauthorizedError": ".errors", "UninstallIntegrationResponse": ".integrationsapi", + "UpcomingInvoiceResponseData": ".types", "UpdateAddOnRequestBody": ".types", "UpdateApiKeyResponse": ".accounts", "UpdateAutoTopupOverrideRequestBody": ".types", @@ -1622,6 +1671,7 @@ "UpdateFeatureResponse": ".features", "UpdateFlagResponse": ".features", "UpdateFlagRulesResponse": ".features", + "UpdateOnboardingStateResponse": ".accounts", "UpdatePayInAdvanceRequestBody": ".types", "UpdatePlanBundleResponse": ".planbundle", "UpdatePlanEntitlementResponse": ".entitlements", @@ -1747,6 +1797,7 @@ def __dir__(): "AuditLogListResponseData", "AuditLogResponseData", "BadRequestError", + "BillingCollectionMethod", "BillingCouponResponseData", "BillingCreditAutoTopupAvailability", "BillingCreditBundleResponseData", @@ -1820,6 +1871,7 @@ def __dir__(): "CheckFlagsBulkResponseData", "CheckFlagsResponse", "CheckFlagsResponseData", + "CheckoutBundlePurchaseBehavior", "CheckoutDataResponseData", "CheckoutFieldInput", "CheckoutFieldResponseData", @@ -1912,6 +1964,8 @@ def __dir__(): "CountEntityKeysResponse", "CountEntityTraitDefinitionsParams", "CountEntityTraitDefinitionsResponse", + "CountEntityTraitsParams", + "CountEntityTraitsResponse", "CountFeatureCompaniesParams", "CountFeatureCompaniesResponse", "CountFeatureUsageParams", @@ -2042,6 +2096,7 @@ def __dir__(): "DeleteComponentResponse", "DeleteCreditBundleResponse", "DeleteEntityKeyDefinitionResponse", + "DeleteEntityTraitDefinitionResponse", "DeleteEnvironmentResponse", "DeleteFeatureResponse", "DeleteFlagResponse", @@ -2067,6 +2122,7 @@ def __dir__(): "EntityKeyDetailResponseData", "EntityKeyResponseData", "EntityTraitDefinitionResponseData", + "EntityTraitDefinitionUsage", "EntityTraitDetailResponseData", "EntityTraitResponseData", "EntityTraitValue", @@ -2101,6 +2157,7 @@ def __dir__(): "FeatureResponseData", "FeatureType", "FeatureUsageDetailResponseData", + "FeatureUsageHistoryResponseData", "FeatureUsageLegacyResponseData", "FeatureUsageResponseData", "FeatureUsageTimeSeriesResponseData", @@ -2135,6 +2192,7 @@ def __dir__(): "GetDataExportResponse", "GetDerivedFeaturesResponse", "GetEntityTraitDefinitionResponse", + "GetEntityTraitDefinitionUsageResponse", "GetEntityTraitValuesParams", "GetEntityTraitValuesResponse", "GetEnvironmentFeatureUsageTimeSeriesParams", @@ -2153,6 +2211,8 @@ def __dir__(): "GetFlagResponse", "GetIntegrationWebhookUrlResponse", "GetMigrationResponse", + "GetOnboardingStateResp", + "GetOnboardingStateResponse", "GetOrCreateCompanyMembershipResponse", "GetOrCreateEntityTraitDefinitionResponse", "GetPlanChangeResponse", @@ -2268,6 +2328,8 @@ def __dir__(): "ListEventsResponse", "ListFeatureCompaniesParams", "ListFeatureCompaniesResponse", + "ListFeatureUsageHistoryParams", + "ListFeatureUsageHistoryResponse", "ListFeatureUsageParams", "ListFeatureUsageResponse", "ListFeatureUsersParams", @@ -2325,12 +2387,21 @@ def __dir__(): "MetricPeriodMonthReset", "MetronomeIntegrationConfig", "MigrationErrorCode", + "MigrationProrationBehavior", "MrrResponseData", "NotFoundError", + "OnboardingMilestone", + "OnboardingMilestoneView", + "OnboardingPath", + "OnboardingRequirement", + "OnboardingRequirementStatus", + "OnboardingRequirementView", + "OnboardingTrack", "OrbIntegrationConfig", "OrderedPlansInGroup", "PaymentMethodRequestBody", "PaymentMethodResponseData", + "PlanBillingSource", "PlanBundleAction", "PlanBundleCreditGrantRequestBody", "PlanBundleEntitlementRequestBody", @@ -2373,6 +2444,8 @@ def __dir__(): "PlanVersionSnapshotView", "PlanVersionStatus", "PlanViewPublicResponseData", + "PreflightEventUsageRequestBody", + "PreflightRequestBody", "PreviewCheckoutInternalResponse", "PreviewComponentDataParams", "PreviewComponentDataResponse", @@ -2461,6 +2534,7 @@ def __dir__(): "TrialStatus", "UnauthorizedError", "UninstallIntegrationResponse", + "UpcomingInvoiceResponseData", "UpdateAddOnRequestBody", "UpdateApiKeyResponse", "UpdateAutoTopupOverrideRequestBody", @@ -2482,6 +2556,7 @@ def __dir__(): "UpdateFeatureResponse", "UpdateFlagResponse", "UpdateFlagRulesResponse", + "UpdateOnboardingStateResponse", "UpdatePayInAdvanceRequestBody", "UpdatePlanBundleResponse", "UpdatePlanEntitlementResponse", diff --git a/src/schematic/accounts/__init__.py b/src/schematic/accounts/__init__.py index 28b75c7..7e1d405 100644 --- a/src/schematic/accounts/__init__.py +++ b/src/schematic/accounts/__init__.py @@ -21,6 +21,7 @@ GetApiKeyResponse, GetAuditLogResponse, GetEnvironmentResponse, + GetOnboardingStateResponse, GetWhoAmIResponse, ListAccountMembersParams, ListAccountMembersResponse, @@ -33,6 +34,7 @@ QuickstartResponse, UpdateApiKeyResponse, UpdateEnvironmentResponse, + UpdateOnboardingStateResponse, ) _dynamic_imports: typing.Dict[str, str] = { "CountAccountMembersParams": ".types", @@ -49,6 +51,7 @@ "GetApiKeyResponse": ".types", "GetAuditLogResponse": ".types", "GetEnvironmentResponse": ".types", + "GetOnboardingStateResponse": ".types", "GetWhoAmIResponse": ".types", "ListAccountMembersParams": ".types", "ListAccountMembersResponse": ".types", @@ -61,6 +64,7 @@ "QuickstartResponse": ".types", "UpdateApiKeyResponse": ".types", "UpdateEnvironmentResponse": ".types", + "UpdateOnboardingStateResponse": ".types", } @@ -100,6 +104,7 @@ def __dir__(): "GetApiKeyResponse", "GetAuditLogResponse", "GetEnvironmentResponse", + "GetOnboardingStateResponse", "GetWhoAmIResponse", "ListAccountMembersParams", "ListAccountMembersResponse", @@ -112,4 +117,5 @@ def __dir__(): "QuickstartResponse", "UpdateApiKeyResponse", "UpdateEnvironmentResponse", + "UpdateOnboardingStateResponse", ] diff --git a/src/schematic/accounts/client.py b/src/schematic/accounts/client.py index e5dd1ed..760fd4c 100644 --- a/src/schematic/accounts/client.py +++ b/src/schematic/accounts/client.py @@ -8,6 +8,8 @@ from ..types.account_member_role import AccountMemberRole from ..types.actor_type import ActorType from ..types.environment_type import EnvironmentType +from ..types.onboarding_path import OnboardingPath +from ..types.onboarding_track import OnboardingTrack from .raw_client import AsyncRawAccountsClient, RawAccountsClient from .types.count_account_members_response import CountAccountMembersResponse from .types.count_api_keys_response import CountApiKeysResponse @@ -20,6 +22,7 @@ from .types.get_api_key_response import GetApiKeyResponse from .types.get_audit_log_response import GetAuditLogResponse from .types.get_environment_response import GetEnvironmentResponse +from .types.get_onboarding_state_response import GetOnboardingStateResponse from .types.get_who_am_i_response import GetWhoAmIResponse from .types.list_account_members_response import ListAccountMembersResponse from .types.list_api_keys_response import ListApiKeysResponse @@ -28,6 +31,7 @@ from .types.quickstart_response import QuickstartResponse from .types.update_api_key_response import UpdateApiKeyResponse from .types.update_environment_response import UpdateEnvironmentResponse +from .types.update_onboarding_state_response import UpdateOnboardingStateResponse # this is used as the default value for optional parameters OMIT = typing.cast(typing.Any, ...) @@ -821,6 +825,78 @@ def delete_environment( _response = self._raw_client.delete_environment(environment_id, request_options=request_options) return _response.data + def get_onboarding_state( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> GetOnboardingStateResponse: + """ + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + GetOnboardingStateResponse + OK + + Examples + -------- + from schematic import Schematic + + client = Schematic( + api_key="YOUR_API_KEY", + ) + client.accounts.get_onboarding_state() + """ + _response = self._raw_client.get_onboarding_state(request_options=request_options) + return _response.data + + def update_onboarding_state( + self, + *, + path: typing.Optional[OnboardingPath] = OMIT, + pricing_page_url: typing.Optional[str] = OMIT, + track: typing.Optional[OnboardingTrack] = OMIT, + website_url: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> UpdateOnboardingStateResponse: + """ + Parameters + ---------- + path : typing.Optional[OnboardingPath] + + pricing_page_url : typing.Optional[str] + + track : typing.Optional[OnboardingTrack] + + website_url : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + UpdateOnboardingStateResponse + OK + + Examples + -------- + from schematic import Schematic + + client = Schematic( + api_key="YOUR_API_KEY", + ) + client.accounts.update_onboarding_state() + """ + _response = self._raw_client.update_onboarding_state( + path=path, + pricing_page_url=pricing_page_url, + track=track, + website_url=website_url, + request_options=request_options, + ) + return _response.data + def quickstart(self, *, request_options: typing.Optional[RequestOptions] = None) -> QuickstartResponse: """ Parameters @@ -1792,6 +1868,94 @@ async def main() -> None: _response = await self._raw_client.delete_environment(environment_id, request_options=request_options) return _response.data + async def get_onboarding_state( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> GetOnboardingStateResponse: + """ + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + GetOnboardingStateResponse + OK + + Examples + -------- + import asyncio + + from schematic import AsyncSchematic + + client = AsyncSchematic( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.accounts.get_onboarding_state() + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_onboarding_state(request_options=request_options) + return _response.data + + async def update_onboarding_state( + self, + *, + path: typing.Optional[OnboardingPath] = OMIT, + pricing_page_url: typing.Optional[str] = OMIT, + track: typing.Optional[OnboardingTrack] = OMIT, + website_url: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> UpdateOnboardingStateResponse: + """ + Parameters + ---------- + path : typing.Optional[OnboardingPath] + + pricing_page_url : typing.Optional[str] + + track : typing.Optional[OnboardingTrack] + + website_url : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + UpdateOnboardingStateResponse + OK + + Examples + -------- + import asyncio + + from schematic import AsyncSchematic + + client = AsyncSchematic( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.accounts.update_onboarding_state() + + + asyncio.run(main()) + """ + _response = await self._raw_client.update_onboarding_state( + path=path, + pricing_page_url=pricing_page_url, + track=track, + website_url=website_url, + request_options=request_options, + ) + return _response.data + async def quickstart(self, *, request_options: typing.Optional[RequestOptions] = None) -> QuickstartResponse: """ Parameters diff --git a/src/schematic/accounts/raw_client.py b/src/schematic/accounts/raw_client.py index 1ee1ed7..d5c0121 100644 --- a/src/schematic/accounts/raw_client.py +++ b/src/schematic/accounts/raw_client.py @@ -21,6 +21,8 @@ from ..types.actor_type import ActorType from ..types.api_error import ApiError as types_api_error_ApiError from ..types.environment_type import EnvironmentType +from ..types.onboarding_path import OnboardingPath +from ..types.onboarding_track import OnboardingTrack from .types.count_account_members_response import CountAccountMembersResponse from .types.count_api_keys_response import CountApiKeysResponse from .types.count_audit_logs_response import CountAuditLogsResponse @@ -32,6 +34,7 @@ from .types.get_api_key_response import GetApiKeyResponse from .types.get_audit_log_response import GetAuditLogResponse from .types.get_environment_response import GetEnvironmentResponse +from .types.get_onboarding_state_response import GetOnboardingStateResponse from .types.get_who_am_i_response import GetWhoAmIResponse from .types.list_account_members_response import ListAccountMembersResponse from .types.list_api_keys_response import ListApiKeysResponse @@ -40,6 +43,7 @@ from .types.quickstart_response import QuickstartResponse from .types.update_api_key_response import UpdateApiKeyResponse from .types.update_environment_response import UpdateEnvironmentResponse +from .types.update_onboarding_state_response import UpdateOnboardingStateResponse from pydantic import ValidationError # this is used as the default value for optional parameters @@ -1943,6 +1947,213 @@ def delete_environment( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) + def get_onboarding_state( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[GetOnboardingStateResponse]: + """ + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[GetOnboardingStateResponse] + OK + """ + _response = self._client_wrapper.httpx_client.request( + "onboarding-state", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + GetOnboardingStateResponse, + parse_obj_as( + type_=GetOnboardingStateResponse, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_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 core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def update_onboarding_state( + self, + *, + path: typing.Optional[OnboardingPath] = OMIT, + pricing_page_url: typing.Optional[str] = OMIT, + track: typing.Optional[OnboardingTrack] = OMIT, + website_url: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[UpdateOnboardingStateResponse]: + """ + Parameters + ---------- + path : typing.Optional[OnboardingPath] + + pricing_page_url : typing.Optional[str] + + track : typing.Optional[OnboardingTrack] + + website_url : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[UpdateOnboardingStateResponse] + OK + """ + _response = self._client_wrapper.httpx_client.request( + "onboarding-state", + method="POST", + json={ + "path": path, + "pricing_page_url": pricing_page_url, + "track": track, + "website_url": website_url, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + UpdateOnboardingStateResponse, + parse_obj_as( + type_=UpdateOnboardingStateResponse, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_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 core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + def quickstart( self, *, request_options: typing.Optional[RequestOptions] = None ) -> HttpResponse[QuickstartResponse]: @@ -4024,6 +4235,213 @@ async def delete_environment( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) + async def get_onboarding_state( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[GetOnboardingStateResponse]: + """ + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[GetOnboardingStateResponse] + OK + """ + _response = await self._client_wrapper.httpx_client.request( + "onboarding-state", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + GetOnboardingStateResponse, + parse_obj_as( + type_=GetOnboardingStateResponse, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_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 core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + async def update_onboarding_state( + self, + *, + path: typing.Optional[OnboardingPath] = OMIT, + pricing_page_url: typing.Optional[str] = OMIT, + track: typing.Optional[OnboardingTrack] = OMIT, + website_url: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[UpdateOnboardingStateResponse]: + """ + Parameters + ---------- + path : typing.Optional[OnboardingPath] + + pricing_page_url : typing.Optional[str] + + track : typing.Optional[OnboardingTrack] + + website_url : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[UpdateOnboardingStateResponse] + OK + """ + _response = await self._client_wrapper.httpx_client.request( + "onboarding-state", + method="POST", + json={ + "path": path, + "pricing_page_url": pricing_page_url, + "track": track, + "website_url": website_url, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + UpdateOnboardingStateResponse, + parse_obj_as( + type_=UpdateOnboardingStateResponse, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_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 core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + async def quickstart( self, *, request_options: typing.Optional[RequestOptions] = None ) -> AsyncHttpResponse[QuickstartResponse]: diff --git a/src/schematic/accounts/types/__init__.py b/src/schematic/accounts/types/__init__.py index 69f8120..9216ff8 100644 --- a/src/schematic/accounts/types/__init__.py +++ b/src/schematic/accounts/types/__init__.py @@ -20,6 +20,7 @@ from .get_api_key_response import GetApiKeyResponse from .get_audit_log_response import GetAuditLogResponse from .get_environment_response import GetEnvironmentResponse + from .get_onboarding_state_response import GetOnboardingStateResponse from .get_who_am_i_response import GetWhoAmIResponse from .list_account_members_params import ListAccountMembersParams from .list_account_members_response import ListAccountMembersResponse @@ -32,6 +33,7 @@ from .quickstart_response import QuickstartResponse from .update_api_key_response import UpdateApiKeyResponse from .update_environment_response import UpdateEnvironmentResponse + from .update_onboarding_state_response import UpdateOnboardingStateResponse _dynamic_imports: typing.Dict[str, str] = { "CountAccountMembersParams": ".count_account_members_params", "CountAccountMembersResponse": ".count_account_members_response", @@ -47,6 +49,7 @@ "GetApiKeyResponse": ".get_api_key_response", "GetAuditLogResponse": ".get_audit_log_response", "GetEnvironmentResponse": ".get_environment_response", + "GetOnboardingStateResponse": ".get_onboarding_state_response", "GetWhoAmIResponse": ".get_who_am_i_response", "ListAccountMembersParams": ".list_account_members_params", "ListAccountMembersResponse": ".list_account_members_response", @@ -59,6 +62,7 @@ "QuickstartResponse": ".quickstart_response", "UpdateApiKeyResponse": ".update_api_key_response", "UpdateEnvironmentResponse": ".update_environment_response", + "UpdateOnboardingStateResponse": ".update_onboarding_state_response", } @@ -98,6 +102,7 @@ def __dir__(): "GetApiKeyResponse", "GetAuditLogResponse", "GetEnvironmentResponse", + "GetOnboardingStateResponse", "GetWhoAmIResponse", "ListAccountMembersParams", "ListAccountMembersResponse", @@ -110,4 +115,5 @@ def __dir__(): "QuickstartResponse", "UpdateApiKeyResponse", "UpdateEnvironmentResponse", + "UpdateOnboardingStateResponse", ] diff --git a/src/schematic/accounts/types/get_onboarding_state_response.py b/src/schematic/accounts/types/get_onboarding_state_response.py new file mode 100644 index 0000000..65850d4 --- /dev/null +++ b/src/schematic/accounts/types/get_onboarding_state_response.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 ...types.get_onboarding_state_resp import GetOnboardingStateResp + + +class GetOnboardingStateResponse(UniversalBaseModel): + data: GetOnboardingStateResp + params: typing.Dict[str, typing.Any] = pydantic.Field() + """ + Input parameters + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/schematic/accounts/types/update_onboarding_state_response.py b/src/schematic/accounts/types/update_onboarding_state_response.py new file mode 100644 index 0000000..83cfe44 --- /dev/null +++ b/src/schematic/accounts/types/update_onboarding_state_response.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 ...types.get_onboarding_state_resp import GetOnboardingStateResp + + +class UpdateOnboardingStateResponse(UniversalBaseModel): + data: GetOnboardingStateResp + params: typing.Dict[str, typing.Any] = pydantic.Field() + """ + Input parameters + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/schematic/base_client.py b/src/schematic/base_client.py index 2698978..cead9ce 100644 --- a/src/schematic/base_client.py +++ b/src/schematic/base_client.py @@ -64,6 +64,12 @@ class BaseSchematic: max_retries : typing.Optional[int] The default maximum number of retries for failed requests. Defaults to 2. Per-request `max_retries` in `request_options` takes precedence over this value. + stream_reconnection_enabled : typing.Optional[bool] + Whether to automatically reconnect on stream disconnection for resumable streaming endpoints. Defaults to True. Per-request `stream_reconnection_enabled` in `request_options` takes precedence over this value. + + max_stream_reconnection_attempts : typing.Optional[int] + The maximum number of reconnection attempts for resumable streaming endpoints. Defaults to no limit. Per-request `max_stream_reconnection_attempts` in `request_options` takes precedence over this value. + 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. @@ -91,13 +97,13 @@ def __init__( headers: typing.Optional[typing.Dict[str, str]] = None, timeout: typing.Optional[float] = None, max_retries: typing.Optional[int] = None, + stream_reconnection_enabled: typing.Optional[bool] = None, + max_stream_reconnection_attempts: typing.Optional[int] = 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 - ) + _defaulted_timeout = timeout if timeout is not None else 60 if httpx_client is None else None _defaulted_max_retries = max_retries if max_retries is not None else 2 self._client_wrapper = SyncClientWrapper( base_url=_get_base_url(base_url=base_url, environment=environment), @@ -110,6 +116,8 @@ def __init__( else httpx.Client(timeout=_defaulted_timeout), timeout=_defaulted_timeout, max_retries=_defaulted_max_retries, + stream_reconnection_enabled=stream_reconnection_enabled, + max_stream_reconnection_attempts=max_stream_reconnection_attempts, logging=logging, ) self._raw_client = RawBaseSchematic(client_wrapper=self._client_wrapper) @@ -393,6 +401,12 @@ class AsyncBaseSchematic: max_retries : typing.Optional[int] The default maximum number of retries for failed requests. Defaults to 2. Per-request `max_retries` in `request_options` takes precedence over this value. + stream_reconnection_enabled : typing.Optional[bool] + Whether to automatically reconnect on stream disconnection for resumable streaming endpoints. Defaults to True. Per-request `stream_reconnection_enabled` in `request_options` takes precedence over this value. + + max_stream_reconnection_attempts : typing.Optional[int] + The maximum number of reconnection attempts for resumable streaming endpoints. Defaults to no limit. Per-request `max_stream_reconnection_attempts` in `request_options` takes precedence over this value. + 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. @@ -420,13 +434,13 @@ def __init__( headers: typing.Optional[typing.Dict[str, str]] = None, timeout: typing.Optional[float] = None, max_retries: typing.Optional[int] = None, + stream_reconnection_enabled: typing.Optional[bool] = None, + max_stream_reconnection_attempts: typing.Optional[int] = 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 - ) + _defaulted_timeout = timeout if timeout is not None else 60 if httpx_client is None else None _defaulted_max_retries = max_retries if max_retries is not None else 2 self._client_wrapper = AsyncClientWrapper( base_url=_get_base_url(base_url=base_url, environment=environment), @@ -437,6 +451,8 @@ def __init__( else _make_default_async_client(timeout=_defaulted_timeout, follow_redirects=follow_redirects), timeout=_defaulted_timeout, max_retries=_defaulted_max_retries, + stream_reconnection_enabled=stream_reconnection_enabled, + max_stream_reconnection_attempts=max_stream_reconnection_attempts, logging=logging, ) self._raw_client = AsyncRawBaseSchematic(client_wrapper=self._client_wrapper) diff --git a/src/schematic/checkout/client.py b/src/schematic/checkout/client.py index f2b591a..f66a17c 100644 --- a/src/schematic/checkout/client.py +++ b/src/schematic/checkout/client.py @@ -5,6 +5,7 @@ from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper from ..core.request_options import RequestOptions +from ..types.billing_collection_method import BillingCollectionMethod from ..types.checkout_field_value import CheckoutFieldValue from ..types.customer_billing_address import CustomerBillingAddress from ..types.plan_selection import PlanSelection @@ -440,15 +441,22 @@ def manage_plan( credit_bundles: typing.Sequence[UpdateCreditBundleRequestBody], custom_field_values: typing.Sequence[CheckoutFieldValue], pay_in_advance_entitlements: typing.Sequence[UpdatePayInAdvanceRequestBody], + activate_on_payment: typing.Optional[bool] = OMIT, base_plan_id: typing.Optional[str] = OMIT, base_plan_price_id: typing.Optional[str] = OMIT, base_plan_version_id: typing.Optional[str] = OMIT, + billing_cycle_anchor: typing.Optional[dt.datetime] = OMIT, + billing_email: typing.Optional[str] = OMIT, billing_entity_id: typing.Optional[str] = OMIT, cancel_immediately: typing.Optional[bool] = OMIT, + collection_method: typing.Optional[BillingCollectionMethod] = OMIT, coupon_external_id: typing.Optional[str] = OMIT, + days_until_due: typing.Optional[int] = OMIT, payment_method_external_id: typing.Optional[str] = OMIT, promo_code: typing.Optional[str] = OMIT, prorate: typing.Optional[bool] = OMIT, + prorate_first_period: typing.Optional[bool] = OMIT, + send_invoice: typing.Optional[bool] = OMIT, trial_end: typing.Optional[dt.datetime] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> ManagePlanResponse: @@ -465,20 +473,35 @@ def manage_plan( pay_in_advance_entitlements : typing.Sequence[UpdatePayInAdvanceRequestBody] + activate_on_payment : typing.Optional[bool] + If true, the company gets the plan only once the first invoice is paid. Only applies to an invoiced subscription. Defaults to false. + base_plan_id : typing.Optional[str] base_plan_price_id : typing.Optional[str] base_plan_version_id : typing.Optional[str] + billing_cycle_anchor : typing.Optional[dt.datetime] + The date the subscription's billing period renews on. Only honored when starting a new subscription; changing the anchor on an existing subscription is not supported. + + billing_email : typing.Optional[str] + Address the invoice is sent to. Required when collection_method is send_invoice. + billing_entity_id : typing.Optional[str] The company that pays for this subscription. Must already have a Stripe customer. Only honored when starting a new subscription. cancel_immediately : typing.Optional[bool] If false, subscription cancels at period end. Only applies when removing all plans. Defaults to true. + collection_method : typing.Optional[BillingCollectionMethod] + How the subscription is paid: charged to a payment method on file, or invoiced with payment terms. Invoicing is only available when starting a new subscription. Defaults to charge_automatically. + coupon_external_id : typing.Optional[str] + days_until_due : typing.Optional[int] + Payment terms in days for an invoiced subscription. Defaults to 30. + payment_method_external_id : typing.Optional[str] promo_code : typing.Optional[str] @@ -486,6 +509,12 @@ def manage_plan( prorate : typing.Optional[bool] If true and cancel_immediately is true, issue prorated credit. Only applies when removing all plans. Defaults to true. + prorate_first_period : typing.Optional[bool] + When true, the partial period between the subscription starting and its renewal date is billed pro rata straight away. When false that period is free and no invoice is raised until the renewal date. Only applies alongside billing_cycle_anchor. Defaults to true. + + send_invoice : typing.Optional[bool] + Whether Stripe emails the invoice when it is finalized. Only applies to an invoiced subscription. Defaults to true. + trial_end : typing.Optional[dt.datetime] request_options : typing.Optional[RequestOptions] @@ -542,15 +571,22 @@ def manage_plan( credit_bundles=credit_bundles, custom_field_values=custom_field_values, pay_in_advance_entitlements=pay_in_advance_entitlements, + activate_on_payment=activate_on_payment, base_plan_id=base_plan_id, base_plan_price_id=base_plan_price_id, base_plan_version_id=base_plan_version_id, + billing_cycle_anchor=billing_cycle_anchor, + billing_email=billing_email, billing_entity_id=billing_entity_id, cancel_immediately=cancel_immediately, + collection_method=collection_method, coupon_external_id=coupon_external_id, + days_until_due=days_until_due, payment_method_external_id=payment_method_external_id, promo_code=promo_code, prorate=prorate, + prorate_first_period=prorate_first_period, + send_invoice=send_invoice, trial_end=trial_end, request_options=request_options, ) @@ -564,15 +600,22 @@ def preview_manage_plan( credit_bundles: typing.Sequence[UpdateCreditBundleRequestBody], custom_field_values: typing.Sequence[CheckoutFieldValue], pay_in_advance_entitlements: typing.Sequence[UpdatePayInAdvanceRequestBody], + activate_on_payment: typing.Optional[bool] = OMIT, base_plan_id: typing.Optional[str] = OMIT, base_plan_price_id: typing.Optional[str] = OMIT, base_plan_version_id: typing.Optional[str] = OMIT, + billing_cycle_anchor: typing.Optional[dt.datetime] = OMIT, + billing_email: typing.Optional[str] = OMIT, billing_entity_id: typing.Optional[str] = OMIT, cancel_immediately: typing.Optional[bool] = OMIT, + collection_method: typing.Optional[BillingCollectionMethod] = OMIT, coupon_external_id: typing.Optional[str] = OMIT, + days_until_due: typing.Optional[int] = OMIT, payment_method_external_id: typing.Optional[str] = OMIT, promo_code: typing.Optional[str] = OMIT, prorate: typing.Optional[bool] = OMIT, + prorate_first_period: typing.Optional[bool] = OMIT, + send_invoice: typing.Optional[bool] = OMIT, trial_end: typing.Optional[dt.datetime] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> PreviewManagePlanResponse: @@ -589,20 +632,35 @@ def preview_manage_plan( pay_in_advance_entitlements : typing.Sequence[UpdatePayInAdvanceRequestBody] + activate_on_payment : typing.Optional[bool] + If true, the company gets the plan only once the first invoice is paid. Only applies to an invoiced subscription. Defaults to false. + base_plan_id : typing.Optional[str] base_plan_price_id : typing.Optional[str] base_plan_version_id : typing.Optional[str] + billing_cycle_anchor : typing.Optional[dt.datetime] + The date the subscription's billing period renews on. Only honored when starting a new subscription; changing the anchor on an existing subscription is not supported. + + billing_email : typing.Optional[str] + Address the invoice is sent to. Required when collection_method is send_invoice. + billing_entity_id : typing.Optional[str] The company that pays for this subscription. Must already have a Stripe customer. Only honored when starting a new subscription. cancel_immediately : typing.Optional[bool] If false, subscription cancels at period end. Only applies when removing all plans. Defaults to true. + collection_method : typing.Optional[BillingCollectionMethod] + How the subscription is paid: charged to a payment method on file, or invoiced with payment terms. Invoicing is only available when starting a new subscription. Defaults to charge_automatically. + coupon_external_id : typing.Optional[str] + days_until_due : typing.Optional[int] + Payment terms in days for an invoiced subscription. Defaults to 30. + payment_method_external_id : typing.Optional[str] promo_code : typing.Optional[str] @@ -610,6 +668,12 @@ def preview_manage_plan( prorate : typing.Optional[bool] If true and cancel_immediately is true, issue prorated credit. Only applies when removing all plans. Defaults to true. + prorate_first_period : typing.Optional[bool] + When true, the partial period between the subscription starting and its renewal date is billed pro rata straight away. When false that period is free and no invoice is raised until the renewal date. Only applies alongside billing_cycle_anchor. Defaults to true. + + send_invoice : typing.Optional[bool] + Whether Stripe emails the invoice when it is finalized. Only applies to an invoiced subscription. Defaults to true. + trial_end : typing.Optional[dt.datetime] request_options : typing.Optional[RequestOptions] @@ -666,15 +730,22 @@ def preview_manage_plan( credit_bundles=credit_bundles, custom_field_values=custom_field_values, pay_in_advance_entitlements=pay_in_advance_entitlements, + activate_on_payment=activate_on_payment, base_plan_id=base_plan_id, base_plan_price_id=base_plan_price_id, base_plan_version_id=base_plan_version_id, + billing_cycle_anchor=billing_cycle_anchor, + billing_email=billing_email, billing_entity_id=billing_entity_id, cancel_immediately=cancel_immediately, + collection_method=collection_method, coupon_external_id=coupon_external_id, + days_until_due=days_until_due, payment_method_external_id=payment_method_external_id, promo_code=promo_code, prorate=prorate, + prorate_first_period=prorate_first_period, + send_invoice=send_invoice, trial_end=trial_end, request_options=request_options, ) @@ -1218,15 +1289,22 @@ async def manage_plan( credit_bundles: typing.Sequence[UpdateCreditBundleRequestBody], custom_field_values: typing.Sequence[CheckoutFieldValue], pay_in_advance_entitlements: typing.Sequence[UpdatePayInAdvanceRequestBody], + activate_on_payment: typing.Optional[bool] = OMIT, base_plan_id: typing.Optional[str] = OMIT, base_plan_price_id: typing.Optional[str] = OMIT, base_plan_version_id: typing.Optional[str] = OMIT, + billing_cycle_anchor: typing.Optional[dt.datetime] = OMIT, + billing_email: typing.Optional[str] = OMIT, billing_entity_id: typing.Optional[str] = OMIT, cancel_immediately: typing.Optional[bool] = OMIT, + collection_method: typing.Optional[BillingCollectionMethod] = OMIT, coupon_external_id: typing.Optional[str] = OMIT, + days_until_due: typing.Optional[int] = OMIT, payment_method_external_id: typing.Optional[str] = OMIT, promo_code: typing.Optional[str] = OMIT, prorate: typing.Optional[bool] = OMIT, + prorate_first_period: typing.Optional[bool] = OMIT, + send_invoice: typing.Optional[bool] = OMIT, trial_end: typing.Optional[dt.datetime] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> ManagePlanResponse: @@ -1243,20 +1321,35 @@ async def manage_plan( pay_in_advance_entitlements : typing.Sequence[UpdatePayInAdvanceRequestBody] + activate_on_payment : typing.Optional[bool] + If true, the company gets the plan only once the first invoice is paid. Only applies to an invoiced subscription. Defaults to false. + base_plan_id : typing.Optional[str] base_plan_price_id : typing.Optional[str] base_plan_version_id : typing.Optional[str] + billing_cycle_anchor : typing.Optional[dt.datetime] + The date the subscription's billing period renews on. Only honored when starting a new subscription; changing the anchor on an existing subscription is not supported. + + billing_email : typing.Optional[str] + Address the invoice is sent to. Required when collection_method is send_invoice. + billing_entity_id : typing.Optional[str] The company that pays for this subscription. Must already have a Stripe customer. Only honored when starting a new subscription. cancel_immediately : typing.Optional[bool] If false, subscription cancels at period end. Only applies when removing all plans. Defaults to true. + collection_method : typing.Optional[BillingCollectionMethod] + How the subscription is paid: charged to a payment method on file, or invoiced with payment terms. Invoicing is only available when starting a new subscription. Defaults to charge_automatically. + coupon_external_id : typing.Optional[str] + days_until_due : typing.Optional[int] + Payment terms in days for an invoiced subscription. Defaults to 30. + payment_method_external_id : typing.Optional[str] promo_code : typing.Optional[str] @@ -1264,6 +1357,12 @@ async def manage_plan( prorate : typing.Optional[bool] If true and cancel_immediately is true, issue prorated credit. Only applies when removing all plans. Defaults to true. + prorate_first_period : typing.Optional[bool] + When true, the partial period between the subscription starting and its renewal date is billed pro rata straight away. When false that period is free and no invoice is raised until the renewal date. Only applies alongside billing_cycle_anchor. Defaults to true. + + send_invoice : typing.Optional[bool] + Whether Stripe emails the invoice when it is finalized. Only applies to an invoiced subscription. Defaults to true. + trial_end : typing.Optional[dt.datetime] request_options : typing.Optional[RequestOptions] @@ -1328,15 +1427,22 @@ async def main() -> None: credit_bundles=credit_bundles, custom_field_values=custom_field_values, pay_in_advance_entitlements=pay_in_advance_entitlements, + activate_on_payment=activate_on_payment, base_plan_id=base_plan_id, base_plan_price_id=base_plan_price_id, base_plan_version_id=base_plan_version_id, + billing_cycle_anchor=billing_cycle_anchor, + billing_email=billing_email, billing_entity_id=billing_entity_id, cancel_immediately=cancel_immediately, + collection_method=collection_method, coupon_external_id=coupon_external_id, + days_until_due=days_until_due, payment_method_external_id=payment_method_external_id, promo_code=promo_code, prorate=prorate, + prorate_first_period=prorate_first_period, + send_invoice=send_invoice, trial_end=trial_end, request_options=request_options, ) @@ -1350,15 +1456,22 @@ async def preview_manage_plan( credit_bundles: typing.Sequence[UpdateCreditBundleRequestBody], custom_field_values: typing.Sequence[CheckoutFieldValue], pay_in_advance_entitlements: typing.Sequence[UpdatePayInAdvanceRequestBody], + activate_on_payment: typing.Optional[bool] = OMIT, base_plan_id: typing.Optional[str] = OMIT, base_plan_price_id: typing.Optional[str] = OMIT, base_plan_version_id: typing.Optional[str] = OMIT, + billing_cycle_anchor: typing.Optional[dt.datetime] = OMIT, + billing_email: typing.Optional[str] = OMIT, billing_entity_id: typing.Optional[str] = OMIT, cancel_immediately: typing.Optional[bool] = OMIT, + collection_method: typing.Optional[BillingCollectionMethod] = OMIT, coupon_external_id: typing.Optional[str] = OMIT, + days_until_due: typing.Optional[int] = OMIT, payment_method_external_id: typing.Optional[str] = OMIT, promo_code: typing.Optional[str] = OMIT, prorate: typing.Optional[bool] = OMIT, + prorate_first_period: typing.Optional[bool] = OMIT, + send_invoice: typing.Optional[bool] = OMIT, trial_end: typing.Optional[dt.datetime] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> PreviewManagePlanResponse: @@ -1375,20 +1488,35 @@ async def preview_manage_plan( pay_in_advance_entitlements : typing.Sequence[UpdatePayInAdvanceRequestBody] + activate_on_payment : typing.Optional[bool] + If true, the company gets the plan only once the first invoice is paid. Only applies to an invoiced subscription. Defaults to false. + base_plan_id : typing.Optional[str] base_plan_price_id : typing.Optional[str] base_plan_version_id : typing.Optional[str] + billing_cycle_anchor : typing.Optional[dt.datetime] + The date the subscription's billing period renews on. Only honored when starting a new subscription; changing the anchor on an existing subscription is not supported. + + billing_email : typing.Optional[str] + Address the invoice is sent to. Required when collection_method is send_invoice. + billing_entity_id : typing.Optional[str] The company that pays for this subscription. Must already have a Stripe customer. Only honored when starting a new subscription. cancel_immediately : typing.Optional[bool] If false, subscription cancels at period end. Only applies when removing all plans. Defaults to true. + collection_method : typing.Optional[BillingCollectionMethod] + How the subscription is paid: charged to a payment method on file, or invoiced with payment terms. Invoicing is only available when starting a new subscription. Defaults to charge_automatically. + coupon_external_id : typing.Optional[str] + days_until_due : typing.Optional[int] + Payment terms in days for an invoiced subscription. Defaults to 30. + payment_method_external_id : typing.Optional[str] promo_code : typing.Optional[str] @@ -1396,6 +1524,12 @@ async def preview_manage_plan( prorate : typing.Optional[bool] If true and cancel_immediately is true, issue prorated credit. Only applies when removing all plans. Defaults to true. + prorate_first_period : typing.Optional[bool] + When true, the partial period between the subscription starting and its renewal date is billed pro rata straight away. When false that period is free and no invoice is raised until the renewal date. Only applies alongside billing_cycle_anchor. Defaults to true. + + send_invoice : typing.Optional[bool] + Whether Stripe emails the invoice when it is finalized. Only applies to an invoiced subscription. Defaults to true. + trial_end : typing.Optional[dt.datetime] request_options : typing.Optional[RequestOptions] @@ -1460,15 +1594,22 @@ async def main() -> None: credit_bundles=credit_bundles, custom_field_values=custom_field_values, pay_in_advance_entitlements=pay_in_advance_entitlements, + activate_on_payment=activate_on_payment, base_plan_id=base_plan_id, base_plan_price_id=base_plan_price_id, base_plan_version_id=base_plan_version_id, + billing_cycle_anchor=billing_cycle_anchor, + billing_email=billing_email, billing_entity_id=billing_entity_id, cancel_immediately=cancel_immediately, + collection_method=collection_method, coupon_external_id=coupon_external_id, + days_until_due=days_until_due, payment_method_external_id=payment_method_external_id, promo_code=promo_code, prorate=prorate, + prorate_first_period=prorate_first_period, + send_invoice=send_invoice, trial_end=trial_end, request_options=request_options, ) diff --git a/src/schematic/checkout/raw_client.py b/src/schematic/checkout/raw_client.py index 35f5b82..0a5d81a 100644 --- a/src/schematic/checkout/raw_client.py +++ b/src/schematic/checkout/raw_client.py @@ -18,6 +18,7 @@ from ..errors.not_found_error import NotFoundError from ..errors.unauthorized_error import UnauthorizedError from ..types.api_error import ApiError as types_api_error_ApiError +from ..types.billing_collection_method import BillingCollectionMethod from ..types.checkout_field_value import CheckoutFieldValue from ..types.customer_billing_address import CustomerBillingAddress from ..types.plan_selection import PlanSelection @@ -740,15 +741,22 @@ def manage_plan( credit_bundles: typing.Sequence[UpdateCreditBundleRequestBody], custom_field_values: typing.Sequence[CheckoutFieldValue], pay_in_advance_entitlements: typing.Sequence[UpdatePayInAdvanceRequestBody], + activate_on_payment: typing.Optional[bool] = OMIT, base_plan_id: typing.Optional[str] = OMIT, base_plan_price_id: typing.Optional[str] = OMIT, base_plan_version_id: typing.Optional[str] = OMIT, + billing_cycle_anchor: typing.Optional[dt.datetime] = OMIT, + billing_email: typing.Optional[str] = OMIT, billing_entity_id: typing.Optional[str] = OMIT, cancel_immediately: typing.Optional[bool] = OMIT, + collection_method: typing.Optional[BillingCollectionMethod] = OMIT, coupon_external_id: typing.Optional[str] = OMIT, + days_until_due: typing.Optional[int] = OMIT, payment_method_external_id: typing.Optional[str] = OMIT, promo_code: typing.Optional[str] = OMIT, prorate: typing.Optional[bool] = OMIT, + prorate_first_period: typing.Optional[bool] = OMIT, + send_invoice: typing.Optional[bool] = OMIT, trial_end: typing.Optional[dt.datetime] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[ManagePlanResponse]: @@ -765,20 +773,35 @@ def manage_plan( pay_in_advance_entitlements : typing.Sequence[UpdatePayInAdvanceRequestBody] + activate_on_payment : typing.Optional[bool] + If true, the company gets the plan only once the first invoice is paid. Only applies to an invoiced subscription. Defaults to false. + base_plan_id : typing.Optional[str] base_plan_price_id : typing.Optional[str] base_plan_version_id : typing.Optional[str] + billing_cycle_anchor : typing.Optional[dt.datetime] + The date the subscription's billing period renews on. Only honored when starting a new subscription; changing the anchor on an existing subscription is not supported. + + billing_email : typing.Optional[str] + Address the invoice is sent to. Required when collection_method is send_invoice. + billing_entity_id : typing.Optional[str] The company that pays for this subscription. Must already have a Stripe customer. Only honored when starting a new subscription. cancel_immediately : typing.Optional[bool] If false, subscription cancels at period end. Only applies when removing all plans. Defaults to true. + collection_method : typing.Optional[BillingCollectionMethod] + How the subscription is paid: charged to a payment method on file, or invoiced with payment terms. Invoicing is only available when starting a new subscription. Defaults to charge_automatically. + coupon_external_id : typing.Optional[str] + days_until_due : typing.Optional[int] + Payment terms in days for an invoiced subscription. Defaults to 30. + payment_method_external_id : typing.Optional[str] promo_code : typing.Optional[str] @@ -786,6 +809,12 @@ def manage_plan( prorate : typing.Optional[bool] If true and cancel_immediately is true, issue prorated credit. Only applies when removing all plans. Defaults to true. + prorate_first_period : typing.Optional[bool] + When true, the partial period between the subscription starting and its renewal date is billed pro rata straight away. When false that period is free and no invoice is raised until the renewal date. Only applies alongside billing_cycle_anchor. Defaults to true. + + send_invoice : typing.Optional[bool] + Whether Stripe emails the invoice when it is finalized. Only applies to an invoiced subscription. Defaults to true. + trial_end : typing.Optional[dt.datetime] request_options : typing.Optional[RequestOptions] @@ -800,14 +829,18 @@ def manage_plan( "manage-plan", method="POST", json={ + "activate_on_payment": activate_on_payment, "add_on_selections": convert_and_respect_annotation_metadata( object_=add_on_selections, annotation=typing.Sequence[PlanSelection], direction="write" ), "base_plan_id": base_plan_id, "base_plan_price_id": base_plan_price_id, "base_plan_version_id": base_plan_version_id, + "billing_cycle_anchor": billing_cycle_anchor, + "billing_email": billing_email, "billing_entity_id": billing_entity_id, "cancel_immediately": cancel_immediately, + "collection_method": collection_method, "company_id": company_id, "coupon_external_id": coupon_external_id, "credit_bundles": convert_and_respect_annotation_metadata( @@ -816,6 +849,7 @@ def manage_plan( "custom_field_values": convert_and_respect_annotation_metadata( object_=custom_field_values, annotation=typing.Sequence[CheckoutFieldValue], direction="write" ), + "days_until_due": days_until_due, "pay_in_advance_entitlements": convert_and_respect_annotation_metadata( object_=pay_in_advance_entitlements, annotation=typing.Sequence[UpdatePayInAdvanceRequestBody], @@ -824,6 +858,8 @@ def manage_plan( "payment_method_external_id": payment_method_external_id, "promo_code": promo_code, "prorate": prorate, + "prorate_first_period": prorate_first_period, + "send_invoice": send_invoice, "trial_end": trial_end, }, headers={ @@ -918,15 +954,22 @@ def preview_manage_plan( credit_bundles: typing.Sequence[UpdateCreditBundleRequestBody], custom_field_values: typing.Sequence[CheckoutFieldValue], pay_in_advance_entitlements: typing.Sequence[UpdatePayInAdvanceRequestBody], + activate_on_payment: typing.Optional[bool] = OMIT, base_plan_id: typing.Optional[str] = OMIT, base_plan_price_id: typing.Optional[str] = OMIT, base_plan_version_id: typing.Optional[str] = OMIT, + billing_cycle_anchor: typing.Optional[dt.datetime] = OMIT, + billing_email: typing.Optional[str] = OMIT, billing_entity_id: typing.Optional[str] = OMIT, cancel_immediately: typing.Optional[bool] = OMIT, + collection_method: typing.Optional[BillingCollectionMethod] = OMIT, coupon_external_id: typing.Optional[str] = OMIT, + days_until_due: typing.Optional[int] = OMIT, payment_method_external_id: typing.Optional[str] = OMIT, promo_code: typing.Optional[str] = OMIT, prorate: typing.Optional[bool] = OMIT, + prorate_first_period: typing.Optional[bool] = OMIT, + send_invoice: typing.Optional[bool] = OMIT, trial_end: typing.Optional[dt.datetime] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[PreviewManagePlanResponse]: @@ -943,20 +986,35 @@ def preview_manage_plan( pay_in_advance_entitlements : typing.Sequence[UpdatePayInAdvanceRequestBody] + activate_on_payment : typing.Optional[bool] + If true, the company gets the plan only once the first invoice is paid. Only applies to an invoiced subscription. Defaults to false. + base_plan_id : typing.Optional[str] base_plan_price_id : typing.Optional[str] base_plan_version_id : typing.Optional[str] + billing_cycle_anchor : typing.Optional[dt.datetime] + The date the subscription's billing period renews on. Only honored when starting a new subscription; changing the anchor on an existing subscription is not supported. + + billing_email : typing.Optional[str] + Address the invoice is sent to. Required when collection_method is send_invoice. + billing_entity_id : typing.Optional[str] The company that pays for this subscription. Must already have a Stripe customer. Only honored when starting a new subscription. cancel_immediately : typing.Optional[bool] If false, subscription cancels at period end. Only applies when removing all plans. Defaults to true. + collection_method : typing.Optional[BillingCollectionMethod] + How the subscription is paid: charged to a payment method on file, or invoiced with payment terms. Invoicing is only available when starting a new subscription. Defaults to charge_automatically. + coupon_external_id : typing.Optional[str] + days_until_due : typing.Optional[int] + Payment terms in days for an invoiced subscription. Defaults to 30. + payment_method_external_id : typing.Optional[str] promo_code : typing.Optional[str] @@ -964,6 +1022,12 @@ def preview_manage_plan( prorate : typing.Optional[bool] If true and cancel_immediately is true, issue prorated credit. Only applies when removing all plans. Defaults to true. + prorate_first_period : typing.Optional[bool] + When true, the partial period between the subscription starting and its renewal date is billed pro rata straight away. When false that period is free and no invoice is raised until the renewal date. Only applies alongside billing_cycle_anchor. Defaults to true. + + send_invoice : typing.Optional[bool] + Whether Stripe emails the invoice when it is finalized. Only applies to an invoiced subscription. Defaults to true. + trial_end : typing.Optional[dt.datetime] request_options : typing.Optional[RequestOptions] @@ -978,14 +1042,18 @@ def preview_manage_plan( "manage-plan/preview", method="POST", json={ + "activate_on_payment": activate_on_payment, "add_on_selections": convert_and_respect_annotation_metadata( object_=add_on_selections, annotation=typing.Sequence[PlanSelection], direction="write" ), "base_plan_id": base_plan_id, "base_plan_price_id": base_plan_price_id, "base_plan_version_id": base_plan_version_id, + "billing_cycle_anchor": billing_cycle_anchor, + "billing_email": billing_email, "billing_entity_id": billing_entity_id, "cancel_immediately": cancel_immediately, + "collection_method": collection_method, "company_id": company_id, "coupon_external_id": coupon_external_id, "credit_bundles": convert_and_respect_annotation_metadata( @@ -994,6 +1062,7 @@ def preview_manage_plan( "custom_field_values": convert_and_respect_annotation_metadata( object_=custom_field_values, annotation=typing.Sequence[CheckoutFieldValue], direction="write" ), + "days_until_due": days_until_due, "pay_in_advance_entitlements": convert_and_respect_annotation_metadata( object_=pay_in_advance_entitlements, annotation=typing.Sequence[UpdatePayInAdvanceRequestBody], @@ -1002,6 +1071,8 @@ def preview_manage_plan( "payment_method_external_id": payment_method_external_id, "promo_code": promo_code, "prorate": prorate, + "prorate_first_period": prorate_first_period, + "send_invoice": send_invoice, "trial_end": trial_end, }, headers={ @@ -2020,15 +2091,22 @@ async def manage_plan( credit_bundles: typing.Sequence[UpdateCreditBundleRequestBody], custom_field_values: typing.Sequence[CheckoutFieldValue], pay_in_advance_entitlements: typing.Sequence[UpdatePayInAdvanceRequestBody], + activate_on_payment: typing.Optional[bool] = OMIT, base_plan_id: typing.Optional[str] = OMIT, base_plan_price_id: typing.Optional[str] = OMIT, base_plan_version_id: typing.Optional[str] = OMIT, + billing_cycle_anchor: typing.Optional[dt.datetime] = OMIT, + billing_email: typing.Optional[str] = OMIT, billing_entity_id: typing.Optional[str] = OMIT, cancel_immediately: typing.Optional[bool] = OMIT, + collection_method: typing.Optional[BillingCollectionMethod] = OMIT, coupon_external_id: typing.Optional[str] = OMIT, + days_until_due: typing.Optional[int] = OMIT, payment_method_external_id: typing.Optional[str] = OMIT, promo_code: typing.Optional[str] = OMIT, prorate: typing.Optional[bool] = OMIT, + prorate_first_period: typing.Optional[bool] = OMIT, + send_invoice: typing.Optional[bool] = OMIT, trial_end: typing.Optional[dt.datetime] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[ManagePlanResponse]: @@ -2045,20 +2123,35 @@ async def manage_plan( pay_in_advance_entitlements : typing.Sequence[UpdatePayInAdvanceRequestBody] + activate_on_payment : typing.Optional[bool] + If true, the company gets the plan only once the first invoice is paid. Only applies to an invoiced subscription. Defaults to false. + base_plan_id : typing.Optional[str] base_plan_price_id : typing.Optional[str] base_plan_version_id : typing.Optional[str] + billing_cycle_anchor : typing.Optional[dt.datetime] + The date the subscription's billing period renews on. Only honored when starting a new subscription; changing the anchor on an existing subscription is not supported. + + billing_email : typing.Optional[str] + Address the invoice is sent to. Required when collection_method is send_invoice. + billing_entity_id : typing.Optional[str] The company that pays for this subscription. Must already have a Stripe customer. Only honored when starting a new subscription. cancel_immediately : typing.Optional[bool] If false, subscription cancels at period end. Only applies when removing all plans. Defaults to true. + collection_method : typing.Optional[BillingCollectionMethod] + How the subscription is paid: charged to a payment method on file, or invoiced with payment terms. Invoicing is only available when starting a new subscription. Defaults to charge_automatically. + coupon_external_id : typing.Optional[str] + days_until_due : typing.Optional[int] + Payment terms in days for an invoiced subscription. Defaults to 30. + payment_method_external_id : typing.Optional[str] promo_code : typing.Optional[str] @@ -2066,6 +2159,12 @@ async def manage_plan( prorate : typing.Optional[bool] If true and cancel_immediately is true, issue prorated credit. Only applies when removing all plans. Defaults to true. + prorate_first_period : typing.Optional[bool] + When true, the partial period between the subscription starting and its renewal date is billed pro rata straight away. When false that period is free and no invoice is raised until the renewal date. Only applies alongside billing_cycle_anchor. Defaults to true. + + send_invoice : typing.Optional[bool] + Whether Stripe emails the invoice when it is finalized. Only applies to an invoiced subscription. Defaults to true. + trial_end : typing.Optional[dt.datetime] request_options : typing.Optional[RequestOptions] @@ -2080,14 +2179,18 @@ async def manage_plan( "manage-plan", method="POST", json={ + "activate_on_payment": activate_on_payment, "add_on_selections": convert_and_respect_annotation_metadata( object_=add_on_selections, annotation=typing.Sequence[PlanSelection], direction="write" ), "base_plan_id": base_plan_id, "base_plan_price_id": base_plan_price_id, "base_plan_version_id": base_plan_version_id, + "billing_cycle_anchor": billing_cycle_anchor, + "billing_email": billing_email, "billing_entity_id": billing_entity_id, "cancel_immediately": cancel_immediately, + "collection_method": collection_method, "company_id": company_id, "coupon_external_id": coupon_external_id, "credit_bundles": convert_and_respect_annotation_metadata( @@ -2096,6 +2199,7 @@ async def manage_plan( "custom_field_values": convert_and_respect_annotation_metadata( object_=custom_field_values, annotation=typing.Sequence[CheckoutFieldValue], direction="write" ), + "days_until_due": days_until_due, "pay_in_advance_entitlements": convert_and_respect_annotation_metadata( object_=pay_in_advance_entitlements, annotation=typing.Sequence[UpdatePayInAdvanceRequestBody], @@ -2104,6 +2208,8 @@ async def manage_plan( "payment_method_external_id": payment_method_external_id, "promo_code": promo_code, "prorate": prorate, + "prorate_first_period": prorate_first_period, + "send_invoice": send_invoice, "trial_end": trial_end, }, headers={ @@ -2198,15 +2304,22 @@ async def preview_manage_plan( credit_bundles: typing.Sequence[UpdateCreditBundleRequestBody], custom_field_values: typing.Sequence[CheckoutFieldValue], pay_in_advance_entitlements: typing.Sequence[UpdatePayInAdvanceRequestBody], + activate_on_payment: typing.Optional[bool] = OMIT, base_plan_id: typing.Optional[str] = OMIT, base_plan_price_id: typing.Optional[str] = OMIT, base_plan_version_id: typing.Optional[str] = OMIT, + billing_cycle_anchor: typing.Optional[dt.datetime] = OMIT, + billing_email: typing.Optional[str] = OMIT, billing_entity_id: typing.Optional[str] = OMIT, cancel_immediately: typing.Optional[bool] = OMIT, + collection_method: typing.Optional[BillingCollectionMethod] = OMIT, coupon_external_id: typing.Optional[str] = OMIT, + days_until_due: typing.Optional[int] = OMIT, payment_method_external_id: typing.Optional[str] = OMIT, promo_code: typing.Optional[str] = OMIT, prorate: typing.Optional[bool] = OMIT, + prorate_first_period: typing.Optional[bool] = OMIT, + send_invoice: typing.Optional[bool] = OMIT, trial_end: typing.Optional[dt.datetime] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[PreviewManagePlanResponse]: @@ -2223,20 +2336,35 @@ async def preview_manage_plan( pay_in_advance_entitlements : typing.Sequence[UpdatePayInAdvanceRequestBody] + activate_on_payment : typing.Optional[bool] + If true, the company gets the plan only once the first invoice is paid. Only applies to an invoiced subscription. Defaults to false. + base_plan_id : typing.Optional[str] base_plan_price_id : typing.Optional[str] base_plan_version_id : typing.Optional[str] + billing_cycle_anchor : typing.Optional[dt.datetime] + The date the subscription's billing period renews on. Only honored when starting a new subscription; changing the anchor on an existing subscription is not supported. + + billing_email : typing.Optional[str] + Address the invoice is sent to. Required when collection_method is send_invoice. + billing_entity_id : typing.Optional[str] The company that pays for this subscription. Must already have a Stripe customer. Only honored when starting a new subscription. cancel_immediately : typing.Optional[bool] If false, subscription cancels at period end. Only applies when removing all plans. Defaults to true. + collection_method : typing.Optional[BillingCollectionMethod] + How the subscription is paid: charged to a payment method on file, or invoiced with payment terms. Invoicing is only available when starting a new subscription. Defaults to charge_automatically. + coupon_external_id : typing.Optional[str] + days_until_due : typing.Optional[int] + Payment terms in days for an invoiced subscription. Defaults to 30. + payment_method_external_id : typing.Optional[str] promo_code : typing.Optional[str] @@ -2244,6 +2372,12 @@ async def preview_manage_plan( prorate : typing.Optional[bool] If true and cancel_immediately is true, issue prorated credit. Only applies when removing all plans. Defaults to true. + prorate_first_period : typing.Optional[bool] + When true, the partial period between the subscription starting and its renewal date is billed pro rata straight away. When false that period is free and no invoice is raised until the renewal date. Only applies alongside billing_cycle_anchor. Defaults to true. + + send_invoice : typing.Optional[bool] + Whether Stripe emails the invoice when it is finalized. Only applies to an invoiced subscription. Defaults to true. + trial_end : typing.Optional[dt.datetime] request_options : typing.Optional[RequestOptions] @@ -2258,14 +2392,18 @@ async def preview_manage_plan( "manage-plan/preview", method="POST", json={ + "activate_on_payment": activate_on_payment, "add_on_selections": convert_and_respect_annotation_metadata( object_=add_on_selections, annotation=typing.Sequence[PlanSelection], direction="write" ), "base_plan_id": base_plan_id, "base_plan_price_id": base_plan_price_id, "base_plan_version_id": base_plan_version_id, + "billing_cycle_anchor": billing_cycle_anchor, + "billing_email": billing_email, "billing_entity_id": billing_entity_id, "cancel_immediately": cancel_immediately, + "collection_method": collection_method, "company_id": company_id, "coupon_external_id": coupon_external_id, "credit_bundles": convert_and_respect_annotation_metadata( @@ -2274,6 +2412,7 @@ async def preview_manage_plan( "custom_field_values": convert_and_respect_annotation_metadata( object_=custom_field_values, annotation=typing.Sequence[CheckoutFieldValue], direction="write" ), + "days_until_due": days_until_due, "pay_in_advance_entitlements": convert_and_respect_annotation_metadata( object_=pay_in_advance_entitlements, annotation=typing.Sequence[UpdatePayInAdvanceRequestBody], @@ -2282,6 +2421,8 @@ async def preview_manage_plan( "payment_method_external_id": payment_method_external_id, "promo_code": promo_code, "prorate": prorate, + "prorate_first_period": prorate_first_period, + "send_invoice": send_invoice, "trial_end": trial_end, }, headers={ diff --git a/src/schematic/companies/__init__.py b/src/schematic/companies/__init__.py index 0160d0a..80d297b 100644 --- a/src/schematic/companies/__init__.py +++ b/src/schematic/companies/__init__.py @@ -15,6 +15,8 @@ CountEntityKeysResponse, CountEntityTraitDefinitionsParams, CountEntityTraitDefinitionsResponse, + CountEntityTraitsParams, + CountEntityTraitsResponse, CountPlanTraitsParams, CountPlanTraitsResponse, CountUsersParams, @@ -26,6 +28,7 @@ DeleteCompanyParams, DeleteCompanyResponse, DeleteEntityKeyDefinitionResponse, + DeleteEntityTraitDefinitionResponse, DeleteUserByKeysResponse, DeleteUserResponse, GetActiveCompanySubscriptionParams, @@ -36,6 +39,7 @@ GetCompanyBillingEntityResponse, GetCompanyResponse, GetEntityTraitDefinitionResponse, + GetEntityTraitDefinitionUsageResponse, GetEntityTraitValuesParams, GetEntityTraitValuesResponse, GetOrCreateCompanyMembershipResponse, @@ -77,6 +81,8 @@ "CountEntityKeysResponse": ".types", "CountEntityTraitDefinitionsParams": ".types", "CountEntityTraitDefinitionsResponse": ".types", + "CountEntityTraitsParams": ".types", + "CountEntityTraitsResponse": ".types", "CountPlanTraitsParams": ".types", "CountPlanTraitsResponse": ".types", "CountUsersParams": ".types", @@ -88,6 +94,7 @@ "DeleteCompanyParams": ".types", "DeleteCompanyResponse": ".types", "DeleteEntityKeyDefinitionResponse": ".types", + "DeleteEntityTraitDefinitionResponse": ".types", "DeleteUserByKeysResponse": ".types", "DeleteUserResponse": ".types", "GetActiveCompanySubscriptionParams": ".types", @@ -98,6 +105,7 @@ "GetCompanyBillingEntityResponse": ".types", "GetCompanyResponse": ".types", "GetEntityTraitDefinitionResponse": ".types", + "GetEntityTraitDefinitionUsageResponse": ".types", "GetEntityTraitValuesParams": ".types", "GetEntityTraitValuesResponse": ".types", "GetOrCreateCompanyMembershipResponse": ".types", @@ -162,6 +170,8 @@ def __dir__(): "CountEntityKeysResponse", "CountEntityTraitDefinitionsParams", "CountEntityTraitDefinitionsResponse", + "CountEntityTraitsParams", + "CountEntityTraitsResponse", "CountPlanTraitsParams", "CountPlanTraitsResponse", "CountUsersParams", @@ -173,6 +183,7 @@ def __dir__(): "DeleteCompanyParams", "DeleteCompanyResponse", "DeleteEntityKeyDefinitionResponse", + "DeleteEntityTraitDefinitionResponse", "DeleteUserByKeysResponse", "DeleteUserResponse", "GetActiveCompanySubscriptionParams", @@ -183,6 +194,7 @@ def __dir__(): "GetCompanyBillingEntityResponse", "GetCompanyResponse", "GetEntityTraitDefinitionResponse", + "GetEntityTraitDefinitionUsageResponse", "GetEntityTraitValuesParams", "GetEntityTraitValuesResponse", "GetOrCreateCompanyMembershipResponse", diff --git a/src/schematic/companies/client.py b/src/schematic/companies/client.py index d772c11..86f832d 100644 --- a/src/schematic/companies/client.py +++ b/src/schematic/companies/client.py @@ -18,6 +18,7 @@ from .types.count_entity_key_definitions_response import CountEntityKeyDefinitionsResponse from .types.count_entity_keys_response import CountEntityKeysResponse from .types.count_entity_trait_definitions_response import CountEntityTraitDefinitionsResponse +from .types.count_entity_traits_response import CountEntityTraitsResponse from .types.count_plan_traits_response import CountPlanTraitsResponse from .types.count_users_response import CountUsersResponse from .types.create_company_response import CreateCompanyResponse @@ -26,6 +27,7 @@ from .types.delete_company_membership_response import DeleteCompanyMembershipResponse from .types.delete_company_response import DeleteCompanyResponse from .types.delete_entity_key_definition_response import DeleteEntityKeyDefinitionResponse +from .types.delete_entity_trait_definition_response import DeleteEntityTraitDefinitionResponse from .types.delete_user_by_keys_response import DeleteUserByKeysResponse from .types.delete_user_response import DeleteUserResponse from .types.get_active_company_subscription_response import GetActiveCompanySubscriptionResponse @@ -33,6 +35,7 @@ from .types.get_company_billing_entity_response import GetCompanyBillingEntityResponse from .types.get_company_response import GetCompanyResponse from .types.get_entity_trait_definition_response import GetEntityTraitDefinitionResponse +from .types.get_entity_trait_definition_usage_response import GetEntityTraitDefinitionUsageResponse from .types.get_entity_trait_values_response import GetEntityTraitValuesResponse from .types.get_or_create_company_membership_response import GetOrCreateCompanyMembershipResponse from .types.get_or_create_entity_trait_definition_response import GetOrCreateEntityTraitDefinitionResponse @@ -85,6 +88,7 @@ def list_companies( plan_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, plan_version_id: typing.Optional[str] = None, plan_version_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + plan_version_unpublished: typing.Optional[bool] = None, q: typing.Optional[str] = None, sort_order_column: typing.Optional[str] = None, sort_order_direction: typing.Optional[SortDirection] = None, @@ -128,6 +132,9 @@ def list_companies( plan_version_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] Filter companies by one or more plan version IDs (each ID starts with plvr_). Takes precedence over plan_version_id when set. + plan_version_unpublished : typing.Optional[bool] + Filter companies assigned to a plan version that is no longer published, meaning the plan has since moved on to a newer version + q : typing.Optional[str] Search for companies by name, keys or string traits @@ -188,6 +195,7 @@ def list_companies( plan_ids=["plan_ids"], plan_version_id="plan_version_id", plan_version_ids=["plan_version_ids"], + plan_version_unpublished=True, q="q", sort_order_column="sort_order_column", sort_order_direction="asc", @@ -211,6 +219,7 @@ def list_companies( plan_ids=plan_ids, plan_version_id=plan_version_id, plan_version_ids=plan_version_ids, + plan_version_unpublished=plan_version_unpublished, q=q, sort_order_column=sort_order_column, sort_order_direction=sort_order_direction, @@ -237,6 +246,7 @@ def upsert_company( last_seen_at: typing.Optional[dt.datetime] = OMIT, name: typing.Optional[str] = OMIT, prevent_key_remap: typing.Optional[bool] = OMIT, + remove_keys: typing.Optional[typing.Sequence[str]] = OMIT, traits: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, update_only: typing.Optional[bool] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -262,6 +272,9 @@ def upsert_company( prevent_key_remap : typing.Optional[bool] + remove_keys : typing.Optional[typing.Sequence[str]] + Names of keys to remove from the company. Removing a key the company does not have does nothing, and a company must keep at least one key. + traits : typing.Optional[typing.Dict[str, typing.Any]] A map of trait names to trait values @@ -294,6 +307,7 @@ def upsert_company( last_seen_at=last_seen_at, name=name, prevent_key_remap=prevent_key_remap, + remove_keys=remove_keys, traits=traits, update_only=update_only, request_options=request_options, @@ -386,6 +400,7 @@ def count_companies( plan_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, plan_version_id: typing.Optional[str] = None, plan_version_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + plan_version_unpublished: typing.Optional[bool] = None, q: typing.Optional[str] = None, sort_order_column: typing.Optional[str] = None, sort_order_direction: typing.Optional[SortDirection] = None, @@ -429,6 +444,9 @@ def count_companies( plan_version_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] Filter companies by one or more plan version IDs (each ID starts with plvr_). Takes precedence over plan_version_id when set. + plan_version_unpublished : typing.Optional[bool] + Filter companies assigned to a plan version that is no longer published, meaning the plan has since moved on to a newer version + q : typing.Optional[str] Search for companies by name, keys or string traits @@ -489,6 +507,7 @@ def count_companies( plan_ids=["plan_ids"], plan_version_id="plan_version_id", plan_version_ids=["plan_version_ids"], + plan_version_unpublished=True, q="q", sort_order_column="sort_order_column", sort_order_direction="asc", @@ -512,6 +531,7 @@ def count_companies( plan_ids=plan_ids, plan_version_id=plan_version_id, plan_version_ids=plan_version_ids, + plan_version_unpublished=plan_version_unpublished, q=q, sort_order_column=sort_order_column, sort_order_direction=sort_order_direction, @@ -538,6 +558,7 @@ def create_company( last_seen_at: typing.Optional[dt.datetime] = OMIT, name: typing.Optional[str] = OMIT, prevent_key_remap: typing.Optional[bool] = OMIT, + remove_keys: typing.Optional[typing.Sequence[str]] = OMIT, traits: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, update_only: typing.Optional[bool] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -563,6 +584,9 @@ def create_company( prevent_key_remap : typing.Optional[bool] + remove_keys : typing.Optional[typing.Sequence[str]] + Names of keys to remove from the company. Removing a key the company does not have does nothing, and a company must keep at least one key. + traits : typing.Optional[typing.Dict[str, typing.Any]] A map of trait names to trait values @@ -595,6 +619,7 @@ def create_company( last_seen_at=last_seen_at, name=name, prevent_key_remap=prevent_key_remap, + remove_keys=remove_keys, traits=traits, update_only=update_only, request_options=request_options, @@ -669,12 +694,12 @@ def lookup_company( return _response.data def get_company_billing_entity( - self, *, company_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None + self, *, company_id: str, request_options: typing.Optional[RequestOptions] = None ) -> GetCompanyBillingEntityResponse: """ Parameters ---------- - company_id : typing.Optional[str] + company_id : str request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -699,12 +724,12 @@ def get_company_billing_entity( return _response.data def get_billing_entity_child_subscriptions( - self, *, company_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None + self, *, company_id: str, request_options: typing.Optional[RequestOptions] = None ) -> GetBillingEntityChildSubscriptionsResponse: """ Parameters ---------- - company_id : typing.Optional[str] + company_id : str request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1336,6 +1361,72 @@ def update_entity_trait_definition( ) return _response.data + def delete_entity_trait_definition( + self, entity_trait_definition_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> DeleteEntityTraitDefinitionResponse: + """ + Parameters + ---------- + entity_trait_definition_id : str + entity_trait_definition_id + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + DeleteEntityTraitDefinitionResponse + OK + + Examples + -------- + from schematic import Schematic + + client = Schematic( + api_key="YOUR_API_KEY", + ) + client.companies.delete_entity_trait_definition( + entity_trait_definition_id="entity_trait_definition_id", + ) + """ + _response = self._raw_client.delete_entity_trait_definition( + entity_trait_definition_id, request_options=request_options + ) + return _response.data + + def get_entity_trait_definition_usage( + self, entity_trait_definition_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> GetEntityTraitDefinitionUsageResponse: + """ + Parameters + ---------- + entity_trait_definition_id : str + entity_trait_definition_id + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + GetEntityTraitDefinitionUsageResponse + OK + + Examples + -------- + from schematic import Schematic + + client = Schematic( + api_key="YOUR_API_KEY", + ) + client.companies.get_entity_trait_definition_usage( + entity_trait_definition_id="entity_trait_definition_id", + ) + """ + _response = self._raw_client.get_entity_trait_definition_usage( + entity_trait_definition_id, request_options=request_options + ) + return _response.data + def count_entity_trait_definitions( self, *, @@ -1453,6 +1544,59 @@ def get_entity_trait_values( ) return _response.data + def count_entity_traits( + self, + *, + definition_id: typing.Optional[str] = None, + entity_type: typing.Optional[EntityType] = None, + limit: typing.Optional[int] = None, + offset: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> CountEntityTraitsResponse: + """ + Parameters + ---------- + definition_id : typing.Optional[str] + + entity_type : typing.Optional[EntityType] + + limit : typing.Optional[int] + Page limit (default 100) + + offset : typing.Optional[int] + Page offset (default 0) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CountEntityTraitsResponse + OK + + Examples + -------- + from schematic import Schematic + + client = Schematic( + api_key="YOUR_API_KEY", + ) + client.companies.count_entity_traits( + definition_id="definition_id", + entity_type="company", + limit=1000000, + offset=1000000, + ) + """ + _response = self._raw_client.count_entity_traits( + definition_id=definition_id, + entity_type=entity_type, + limit=limit, + offset=offset, + request_options=request_options, + ) + return _response.data + def list_plan_changes( self, *, @@ -1460,7 +1604,6 @@ def list_plan_changes( base_plan_action: typing.Optional[PlanChangeBasePlanAction] = None, company_id: typing.Optional[str] = None, company_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, - plan_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None, @@ -1476,8 +1619,6 @@ def list_plan_changes( company_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] - plan_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] - limit : typing.Optional[int] Page limit (default 100) @@ -1504,7 +1645,6 @@ def list_plan_changes( base_plan_action="fallback", company_id="company_id", company_ids=["company_ids"], - plan_ids=["plan_ids"], limit=1000000, offset=1000000, ) @@ -1514,7 +1654,6 @@ def list_plan_changes( base_plan_action=base_plan_action, company_id=company_id, company_ids=company_ids, - plan_ids=plan_ids, limit=limit, offset=offset, request_options=request_options, @@ -1891,6 +2030,7 @@ def upsert_user( id: typing.Optional[str] = OMIT, last_seen_at: typing.Optional[dt.datetime] = OMIT, name: typing.Optional[str] = OMIT, + remove_keys: typing.Optional[typing.Sequence[str]] = OMIT, traits: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, update_only: typing.Optional[bool] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -1920,6 +2060,9 @@ def upsert_user( name : typing.Optional[str] + remove_keys : typing.Optional[typing.Sequence[str]] + Names of keys to remove from the user. Removing a key the user does not have does nothing, and a user must keep at least one key. + traits : typing.Optional[typing.Dict[str, typing.Any]] A map of trait names to trait values @@ -1953,6 +2096,7 @@ def upsert_user( id=id, last_seen_at=last_seen_at, name=name, + remove_keys=remove_keys, traits=traits, update_only=update_only, request_options=request_options, @@ -2097,6 +2241,7 @@ def create_user( id: typing.Optional[str] = OMIT, last_seen_at: typing.Optional[dt.datetime] = OMIT, name: typing.Optional[str] = OMIT, + remove_keys: typing.Optional[typing.Sequence[str]] = OMIT, traits: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, update_only: typing.Optional[bool] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -2126,6 +2271,9 @@ def create_user( name : typing.Optional[str] + remove_keys : typing.Optional[typing.Sequence[str]] + Names of keys to remove from the user. Removing a key the user does not have does nothing, and a user must keep at least one key. + traits : typing.Optional[typing.Dict[str, typing.Any]] A map of trait names to trait values @@ -2159,6 +2307,7 @@ def create_user( id=id, last_seen_at=last_seen_at, name=name, + remove_keys=remove_keys, traits=traits, update_only=update_only, request_options=request_options, @@ -2253,6 +2402,7 @@ async def list_companies( plan_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, plan_version_id: typing.Optional[str] = None, plan_version_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + plan_version_unpublished: typing.Optional[bool] = None, q: typing.Optional[str] = None, sort_order_column: typing.Optional[str] = None, sort_order_direction: typing.Optional[SortDirection] = None, @@ -2296,6 +2446,9 @@ async def list_companies( plan_version_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] Filter companies by one or more plan version IDs (each ID starts with plvr_). Takes precedence over plan_version_id when set. + plan_version_unpublished : typing.Optional[bool] + Filter companies assigned to a plan version that is no longer published, meaning the plan has since moved on to a newer version + q : typing.Optional[str] Search for companies by name, keys or string traits @@ -2361,6 +2514,7 @@ async def main() -> None: plan_ids=["plan_ids"], plan_version_id="plan_version_id", plan_version_ids=["plan_version_ids"], + plan_version_unpublished=True, q="q", sort_order_column="sort_order_column", sort_order_direction="asc", @@ -2387,6 +2541,7 @@ async def main() -> None: plan_ids=plan_ids, plan_version_id=plan_version_id, plan_version_ids=plan_version_ids, + plan_version_unpublished=plan_version_unpublished, q=q, sort_order_column=sort_order_column, sort_order_direction=sort_order_direction, @@ -2413,6 +2568,7 @@ async def upsert_company( last_seen_at: typing.Optional[dt.datetime] = OMIT, name: typing.Optional[str] = OMIT, prevent_key_remap: typing.Optional[bool] = OMIT, + remove_keys: typing.Optional[typing.Sequence[str]] = OMIT, traits: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, update_only: typing.Optional[bool] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -2438,6 +2594,9 @@ async def upsert_company( prevent_key_remap : typing.Optional[bool] + remove_keys : typing.Optional[typing.Sequence[str]] + Names of keys to remove from the company. Removing a key the company does not have does nothing, and a company must keep at least one key. + traits : typing.Optional[typing.Dict[str, typing.Any]] A map of trait names to trait values @@ -2478,6 +2637,7 @@ async def main() -> None: last_seen_at=last_seen_at, name=name, prevent_key_remap=prevent_key_remap, + remove_keys=remove_keys, traits=traits, update_only=update_only, request_options=request_options, @@ -2586,6 +2746,7 @@ async def count_companies( plan_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, plan_version_id: typing.Optional[str] = None, plan_version_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + plan_version_unpublished: typing.Optional[bool] = None, q: typing.Optional[str] = None, sort_order_column: typing.Optional[str] = None, sort_order_direction: typing.Optional[SortDirection] = None, @@ -2629,6 +2790,9 @@ async def count_companies( plan_version_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] Filter companies by one or more plan version IDs (each ID starts with plvr_). Takes precedence over plan_version_id when set. + plan_version_unpublished : typing.Optional[bool] + Filter companies assigned to a plan version that is no longer published, meaning the plan has since moved on to a newer version + q : typing.Optional[str] Search for companies by name, keys or string traits @@ -2694,6 +2858,7 @@ async def main() -> None: plan_ids=["plan_ids"], plan_version_id="plan_version_id", plan_version_ids=["plan_version_ids"], + plan_version_unpublished=True, q="q", sort_order_column="sort_order_column", sort_order_direction="asc", @@ -2720,6 +2885,7 @@ async def main() -> None: plan_ids=plan_ids, plan_version_id=plan_version_id, plan_version_ids=plan_version_ids, + plan_version_unpublished=plan_version_unpublished, q=q, sort_order_column=sort_order_column, sort_order_direction=sort_order_direction, @@ -2746,6 +2912,7 @@ async def create_company( last_seen_at: typing.Optional[dt.datetime] = OMIT, name: typing.Optional[str] = OMIT, prevent_key_remap: typing.Optional[bool] = OMIT, + remove_keys: typing.Optional[typing.Sequence[str]] = OMIT, traits: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, update_only: typing.Optional[bool] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -2771,6 +2938,9 @@ async def create_company( prevent_key_remap : typing.Optional[bool] + remove_keys : typing.Optional[typing.Sequence[str]] + Names of keys to remove from the company. Removing a key the company does not have does nothing, and a company must keep at least one key. + traits : typing.Optional[typing.Dict[str, typing.Any]] A map of trait names to trait values @@ -2811,6 +2981,7 @@ async def main() -> None: last_seen_at=last_seen_at, name=name, prevent_key_remap=prevent_key_remap, + remove_keys=remove_keys, traits=traits, update_only=update_only, request_options=request_options, @@ -2901,12 +3072,12 @@ async def main() -> None: return _response.data async def get_company_billing_entity( - self, *, company_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None + self, *, company_id: str, request_options: typing.Optional[RequestOptions] = None ) -> GetCompanyBillingEntityResponse: """ Parameters ---------- - company_id : typing.Optional[str] + company_id : str request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -2941,12 +3112,12 @@ async def main() -> None: return _response.data async def get_billing_entity_child_subscriptions( - self, *, company_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None + self, *, company_id: str, request_options: typing.Optional[RequestOptions] = None ) -> GetBillingEntityChildSubscriptionsResponse: """ Parameters ---------- - company_id : typing.Optional[str] + company_id : str request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -3692,6 +3863,88 @@ async def main() -> None: ) return _response.data + async def delete_entity_trait_definition( + self, entity_trait_definition_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> DeleteEntityTraitDefinitionResponse: + """ + Parameters + ---------- + entity_trait_definition_id : str + entity_trait_definition_id + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + DeleteEntityTraitDefinitionResponse + OK + + Examples + -------- + import asyncio + + from schematic import AsyncSchematic + + client = AsyncSchematic( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.companies.delete_entity_trait_definition( + entity_trait_definition_id="entity_trait_definition_id", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.delete_entity_trait_definition( + entity_trait_definition_id, request_options=request_options + ) + return _response.data + + async def get_entity_trait_definition_usage( + self, entity_trait_definition_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> GetEntityTraitDefinitionUsageResponse: + """ + Parameters + ---------- + entity_trait_definition_id : str + entity_trait_definition_id + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + GetEntityTraitDefinitionUsageResponse + OK + + Examples + -------- + import asyncio + + from schematic import AsyncSchematic + + client = AsyncSchematic( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.companies.get_entity_trait_definition_usage( + entity_trait_definition_id="entity_trait_definition_id", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_entity_trait_definition_usage( + entity_trait_definition_id, request_options=request_options + ) + return _response.data + async def count_entity_trait_definitions( self, *, @@ -3825,6 +4078,67 @@ async def main() -> None: ) return _response.data + async def count_entity_traits( + self, + *, + definition_id: typing.Optional[str] = None, + entity_type: typing.Optional[EntityType] = None, + limit: typing.Optional[int] = None, + offset: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> CountEntityTraitsResponse: + """ + Parameters + ---------- + definition_id : typing.Optional[str] + + entity_type : typing.Optional[EntityType] + + limit : typing.Optional[int] + Page limit (default 100) + + offset : typing.Optional[int] + Page offset (default 0) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CountEntityTraitsResponse + OK + + Examples + -------- + import asyncio + + from schematic import AsyncSchematic + + client = AsyncSchematic( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.companies.count_entity_traits( + definition_id="definition_id", + entity_type="company", + limit=1000000, + offset=1000000, + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.count_entity_traits( + definition_id=definition_id, + entity_type=entity_type, + limit=limit, + offset=offset, + request_options=request_options, + ) + return _response.data + async def list_plan_changes( self, *, @@ -3832,7 +4146,6 @@ async def list_plan_changes( base_plan_action: typing.Optional[PlanChangeBasePlanAction] = None, company_id: typing.Optional[str] = None, company_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, - plan_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None, @@ -3848,8 +4161,6 @@ async def list_plan_changes( company_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] - plan_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] - limit : typing.Optional[int] Page limit (default 100) @@ -3881,7 +4192,6 @@ async def main() -> None: base_plan_action="fallback", company_id="company_id", company_ids=["company_ids"], - plan_ids=["plan_ids"], limit=1000000, offset=1000000, ) @@ -3894,7 +4204,6 @@ async def main() -> None: base_plan_action=base_plan_action, company_id=company_id, company_ids=company_ids, - plan_ids=plan_ids, limit=limit, offset=offset, request_options=request_options, @@ -4327,6 +4636,7 @@ async def upsert_user( id: typing.Optional[str] = OMIT, last_seen_at: typing.Optional[dt.datetime] = OMIT, name: typing.Optional[str] = OMIT, + remove_keys: typing.Optional[typing.Sequence[str]] = OMIT, traits: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, update_only: typing.Optional[bool] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -4356,6 +4666,9 @@ async def upsert_user( name : typing.Optional[str] + remove_keys : typing.Optional[typing.Sequence[str]] + Names of keys to remove from the user. Removing a key the user does not have does nothing, and a user must keep at least one key. + traits : typing.Optional[typing.Dict[str, typing.Any]] A map of trait names to trait values @@ -4397,6 +4710,7 @@ async def main() -> None: id=id, last_seen_at=last_seen_at, name=name, + remove_keys=remove_keys, traits=traits, update_only=update_only, request_options=request_options, @@ -4567,6 +4881,7 @@ async def create_user( id: typing.Optional[str] = OMIT, last_seen_at: typing.Optional[dt.datetime] = OMIT, name: typing.Optional[str] = OMIT, + remove_keys: typing.Optional[typing.Sequence[str]] = OMIT, traits: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, update_only: typing.Optional[bool] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -4596,6 +4911,9 @@ async def create_user( name : typing.Optional[str] + remove_keys : typing.Optional[typing.Sequence[str]] + Names of keys to remove from the user. Removing a key the user does not have does nothing, and a user must keep at least one key. + traits : typing.Optional[typing.Dict[str, typing.Any]] A map of trait names to trait values @@ -4637,6 +4955,7 @@ async def main() -> None: id=id, last_seen_at=last_seen_at, name=name, + remove_keys=remove_keys, traits=traits, update_only=update_only, request_options=request_options, diff --git a/src/schematic/companies/raw_client.py b/src/schematic/companies/raw_client.py index 9acaae2..e123323 100644 --- a/src/schematic/companies/raw_client.py +++ b/src/schematic/companies/raw_client.py @@ -30,6 +30,7 @@ from .types.count_entity_key_definitions_response import CountEntityKeyDefinitionsResponse from .types.count_entity_keys_response import CountEntityKeysResponse from .types.count_entity_trait_definitions_response import CountEntityTraitDefinitionsResponse +from .types.count_entity_traits_response import CountEntityTraitsResponse from .types.count_plan_traits_response import CountPlanTraitsResponse from .types.count_users_response import CountUsersResponse from .types.create_company_response import CreateCompanyResponse @@ -38,6 +39,7 @@ from .types.delete_company_membership_response import DeleteCompanyMembershipResponse from .types.delete_company_response import DeleteCompanyResponse from .types.delete_entity_key_definition_response import DeleteEntityKeyDefinitionResponse +from .types.delete_entity_trait_definition_response import DeleteEntityTraitDefinitionResponse from .types.delete_user_by_keys_response import DeleteUserByKeysResponse from .types.delete_user_response import DeleteUserResponse from .types.get_active_company_subscription_response import GetActiveCompanySubscriptionResponse @@ -45,6 +47,7 @@ from .types.get_company_billing_entity_response import GetCompanyBillingEntityResponse from .types.get_company_response import GetCompanyResponse from .types.get_entity_trait_definition_response import GetEntityTraitDefinitionResponse +from .types.get_entity_trait_definition_usage_response import GetEntityTraitDefinitionUsageResponse from .types.get_entity_trait_values_response import GetEntityTraitValuesResponse from .types.get_or_create_company_membership_response import GetOrCreateCompanyMembershipResponse from .types.get_or_create_entity_trait_definition_response import GetOrCreateEntityTraitDefinitionResponse @@ -87,6 +90,7 @@ def list_companies( plan_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, plan_version_id: typing.Optional[str] = None, plan_version_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + plan_version_unpublished: typing.Optional[bool] = None, q: typing.Optional[str] = None, sort_order_column: typing.Optional[str] = None, sort_order_direction: typing.Optional[SortDirection] = None, @@ -130,6 +134,9 @@ def list_companies( plan_version_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] Filter companies by one or more plan version IDs (each ID starts with plvr_). Takes precedence over plan_version_id when set. + plan_version_unpublished : typing.Optional[bool] + Filter companies assigned to a plan version that is no longer published, meaning the plan has since moved on to a newer version + q : typing.Optional[str] Search for companies by name, keys or string traits @@ -186,6 +193,7 @@ def list_companies( "plan_ids": plan_ids, "plan_version_id": plan_version_id, "plan_version_ids": plan_version_ids, + "plan_version_unpublished": plan_version_unpublished, "q": q, "sort_order_column": sort_order_column, "sort_order_direction": sort_order_direction, @@ -289,6 +297,7 @@ def upsert_company( last_seen_at: typing.Optional[dt.datetime] = OMIT, name: typing.Optional[str] = OMIT, prevent_key_remap: typing.Optional[bool] = OMIT, + remove_keys: typing.Optional[typing.Sequence[str]] = OMIT, traits: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, update_only: typing.Optional[bool] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -314,6 +323,9 @@ def upsert_company( prevent_key_remap : typing.Optional[bool] + remove_keys : typing.Optional[typing.Sequence[str]] + Names of keys to remove from the company. Removing a key the company does not have does nothing, and a company must keep at least one key. + traits : typing.Optional[typing.Dict[str, typing.Any]] A map of trait names to trait values @@ -338,6 +350,7 @@ def upsert_company( "last_seen_at": last_seen_at, "name": name, "prevent_key_remap": prevent_key_remap, + "remove_keys": remove_keys, "traits": traits, "update_only": update_only, }, @@ -638,6 +651,7 @@ def count_companies( plan_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, plan_version_id: typing.Optional[str] = None, plan_version_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + plan_version_unpublished: typing.Optional[bool] = None, q: typing.Optional[str] = None, sort_order_column: typing.Optional[str] = None, sort_order_direction: typing.Optional[SortDirection] = None, @@ -681,6 +695,9 @@ def count_companies( plan_version_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] Filter companies by one or more plan version IDs (each ID starts with plvr_). Takes precedence over plan_version_id when set. + plan_version_unpublished : typing.Optional[bool] + Filter companies assigned to a plan version that is no longer published, meaning the plan has since moved on to a newer version + q : typing.Optional[str] Search for companies by name, keys or string traits @@ -737,6 +754,7 @@ def count_companies( "plan_ids": plan_ids, "plan_version_id": plan_version_id, "plan_version_ids": plan_version_ids, + "plan_version_unpublished": plan_version_unpublished, "q": q, "sort_order_column": sort_order_column, "sort_order_direction": sort_order_direction, @@ -840,6 +858,7 @@ def create_company( last_seen_at: typing.Optional[dt.datetime] = OMIT, name: typing.Optional[str] = OMIT, prevent_key_remap: typing.Optional[bool] = OMIT, + remove_keys: typing.Optional[typing.Sequence[str]] = OMIT, traits: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, update_only: typing.Optional[bool] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -865,6 +884,9 @@ def create_company( prevent_key_remap : typing.Optional[bool] + remove_keys : typing.Optional[typing.Sequence[str]] + Names of keys to remove from the company. Removing a key the company does not have does nothing, and a company must keep at least one key. + traits : typing.Optional[typing.Dict[str, typing.Any]] A map of trait names to trait values @@ -889,6 +911,7 @@ def create_company( "last_seen_at": last_seen_at, "name": name, "prevent_key_remap": prevent_key_remap, + "remove_keys": remove_keys, "traits": traits, "update_only": update_only, }, @@ -1181,12 +1204,12 @@ def lookup_company( ) def get_company_billing_entity( - self, *, company_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None + self, *, company_id: str, request_options: typing.Optional[RequestOptions] = None ) -> HttpResponse[GetCompanyBillingEntityResponse]: """ Parameters ---------- - company_id : typing.Optional[str] + company_id : str request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1283,12 +1306,12 @@ def get_company_billing_entity( ) def get_billing_entity_child_subscriptions( - self, *, company_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None + self, *, company_id: str, request_options: typing.Optional[RequestOptions] = None ) -> HttpResponse[GetBillingEntityChildSubscriptionsResponse]: """ Parameters ---------- - company_id : typing.Optional[str] + company_id : str request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -2884,65 +2907,34 @@ def update_entity_trait_definition( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def count_entity_trait_definitions( - self, - *, - entity_type: typing.Optional[EntityType] = None, - ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, - q: typing.Optional[str] = None, - trait_type: typing.Optional[TraitType] = None, - trait_types: typing.Optional[typing.Union[TraitType, typing.Sequence[TraitType]]] = None, - limit: typing.Optional[int] = None, - offset: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[CountEntityTraitDefinitionsResponse]: + def delete_entity_trait_definition( + self, entity_trait_definition_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[DeleteEntityTraitDefinitionResponse]: """ Parameters ---------- - entity_type : typing.Optional[EntityType] - - ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] - - q : typing.Optional[str] - - trait_type : typing.Optional[TraitType] - - trait_types : typing.Optional[typing.Union[TraitType, typing.Sequence[TraitType]]] - - limit : typing.Optional[int] - Page limit (default 100) - - offset : typing.Optional[int] - Page offset (default 0) + entity_trait_definition_id : str + entity_trait_definition_id request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[CountEntityTraitDefinitionsResponse] + HttpResponse[DeleteEntityTraitDefinitionResponse] OK """ _response = self._client_wrapper.httpx_client.request( - "entity-trait-definitions/count", - method="GET", - params={ - "entity_type": entity_type, - "ids": ids, - "q": q, - "trait_type": trait_type, - "trait_types": trait_types, - "limit": limit, - "offset": offset, - }, + f"entity-trait-definitions/{encode_path_param(entity_trait_definition_id)}", + method="DELETE", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - CountEntityTraitDefinitionsResponse, + DeleteEntityTraitDefinitionResponse, parse_obj_as( - type_=CountEntityTraitDefinitionsResponse, # type: ignore + type_=DeleteEntityTraitDefinitionResponse, # type: ignore object_=_response.json(), ), ) @@ -3015,68 +3007,38 @@ def count_entity_trait_definitions( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get_entity_trait_values( - self, - *, - definition_id: str, - q: typing.Optional[str] = None, - limit: typing.Optional[int] = None, - offset: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[GetEntityTraitValuesResponse]: + def get_entity_trait_definition_usage( + self, entity_trait_definition_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[GetEntityTraitDefinitionUsageResponse]: """ Parameters ---------- - definition_id : str - - q : typing.Optional[str] - - limit : typing.Optional[int] - Page limit (default 100) - - offset : typing.Optional[int] - Page offset (default 0) + entity_trait_definition_id : str + entity_trait_definition_id request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[GetEntityTraitValuesResponse] + HttpResponse[GetEntityTraitDefinitionUsageResponse] OK """ _response = self._client_wrapper.httpx_client.request( - "entity-trait-values", + f"entity-trait-definitions/{encode_path_param(entity_trait_definition_id)}/usage", method="GET", - params={ - "definition_id": definition_id, - "q": q, - "limit": limit, - "offset": offset, - }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - GetEntityTraitValuesResponse, + GetEntityTraitDefinitionUsageResponse, parse_obj_as( - type_=GetEntityTraitValuesResponse, # type: ignore + type_=GetEntityTraitDefinitionUsageResponse, # 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( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) if _response.status_code == 401: raise UnauthorizedError( headers=dict(_response.headers), @@ -3134,30 +3096,30 @@ def get_entity_trait_values( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def list_plan_changes( + def count_entity_trait_definitions( self, *, - action: typing.Optional[PlanChangeAction] = None, - base_plan_action: typing.Optional[PlanChangeBasePlanAction] = None, - company_id: typing.Optional[str] = None, - company_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, - plan_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + entity_type: typing.Optional[EntityType] = None, + ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + q: typing.Optional[str] = None, + trait_type: typing.Optional[TraitType] = None, + trait_types: typing.Optional[typing.Union[TraitType, typing.Sequence[TraitType]]] = None, limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[ListPlanChangesResponse]: + ) -> HttpResponse[CountEntityTraitDefinitionsResponse]: """ Parameters ---------- - action : typing.Optional[PlanChangeAction] + entity_type : typing.Optional[EntityType] - base_plan_action : typing.Optional[PlanChangeBasePlanAction] + ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] - company_id : typing.Optional[str] + q : typing.Optional[str] - company_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] + trait_type : typing.Optional[TraitType] - plan_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] + trait_types : typing.Optional[typing.Union[TraitType, typing.Sequence[TraitType]]] limit : typing.Optional[int] Page limit (default 100) @@ -3170,18 +3132,18 @@ def list_plan_changes( Returns ------- - HttpResponse[ListPlanChangesResponse] + HttpResponse[CountEntityTraitDefinitionsResponse] OK """ _response = self._client_wrapper.httpx_client.request( - "plan-changes", + "entity-trait-definitions/count", method="GET", params={ - "action": action, - "base_plan_action": base_plan_action, - "company_id": company_id, - "company_ids": company_ids, - "plan_ids": plan_ids, + "entity_type": entity_type, + "ids": ids, + "q": q, + "trait_type": trait_type, + "trait_types": trait_types, "limit": limit, "offset": offset, }, @@ -3190,9 +3152,9 @@ def list_plan_changes( try: if 200 <= _response.status_code < 300: _data = typing.cast( - ListPlanChangesResponse, + CountEntityTraitDefinitionsResponse, parse_obj_as( - type_=ListPlanChangesResponse, # type: ignore + type_=CountEntityTraitDefinitionsResponse, # type: ignore object_=_response.json(), ), ) @@ -3265,38 +3227,68 @@ def list_plan_changes( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get_plan_change( - self, plan_change_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[GetPlanChangeResponse]: + def get_entity_trait_values( + self, + *, + definition_id: str, + q: typing.Optional[str] = None, + limit: typing.Optional[int] = None, + offset: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[GetEntityTraitValuesResponse]: """ Parameters ---------- - plan_change_id : str - plan_change_id + definition_id : str + + q : typing.Optional[str] + + limit : typing.Optional[int] + Page limit (default 100) + + offset : typing.Optional[int] + Page offset (default 0) request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[GetPlanChangeResponse] + HttpResponse[GetEntityTraitValuesResponse] OK """ _response = self._client_wrapper.httpx_client.request( - f"plan-changes/{encode_path_param(plan_change_id)}", + "entity-trait-values", method="GET", + params={ + "definition_id": definition_id, + "q": q, + "limit": limit, + "offset": offset, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - GetPlanChangeResponse, + GetEntityTraitValuesResponse, parse_obj_as( - type_=GetPlanChangeResponse, # type: ignore + type_=GetEntityTraitValuesResponse, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 401: raise UnauthorizedError( headers=dict(_response.headers), @@ -3354,27 +3346,21 @@ def get_plan_change( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def list_plan_traits( + def count_entity_traits( self, *, - ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, - plan_id: typing.Optional[str] = None, - trait_id: typing.Optional[str] = None, - trait_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + definition_id: typing.Optional[str] = None, + entity_type: typing.Optional[EntityType] = None, limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[ListPlanTraitsResponse]: + ) -> HttpResponse[CountEntityTraitsResponse]: """ Parameters ---------- - ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] - - plan_id : typing.Optional[str] - - trait_id : typing.Optional[str] + definition_id : typing.Optional[str] - trait_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] + entity_type : typing.Optional[EntityType] limit : typing.Optional[int] Page limit (default 100) @@ -3387,17 +3373,15 @@ def list_plan_traits( Returns ------- - HttpResponse[ListPlanTraitsResponse] + HttpResponse[CountEntityTraitsResponse] OK """ _response = self._client_wrapper.httpx_client.request( - "plan-traits", + "entity-traits/count", method="GET", params={ - "ids": ids, - "plan_id": plan_id, - "trait_id": trait_id, - "trait_ids": trait_ids, + "definition_id": definition_id, + "entity_type": entity_type, "limit": limit, "offset": offset, }, @@ -3406,9 +3390,9 @@ def list_plan_traits( try: if 200 <= _response.status_code < 300: _data = typing.cast( - ListPlanTraitsResponse, + CountEntityTraitsResponse, parse_obj_as( - type_=ListPlanTraitsResponse, # type: ignore + type_=CountEntityTraitsResponse, # type: ignore object_=_response.json(), ), ) @@ -3481,38 +3465,76 @@ def list_plan_traits( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get_plan_trait( - self, plan_trait_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[GetPlanTraitResponse]: + def list_plan_changes( + self, + *, + action: typing.Optional[PlanChangeAction] = None, + base_plan_action: typing.Optional[PlanChangeBasePlanAction] = None, + company_id: typing.Optional[str] = None, + company_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + limit: typing.Optional[int] = None, + offset: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ListPlanChangesResponse]: """ Parameters ---------- - plan_trait_id : str - plan_trait_id + action : typing.Optional[PlanChangeAction] + + base_plan_action : typing.Optional[PlanChangeBasePlanAction] + + company_id : typing.Optional[str] + + company_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] + + limit : typing.Optional[int] + Page limit (default 100) + + offset : typing.Optional[int] + Page offset (default 0) request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[GetPlanTraitResponse] + HttpResponse[ListPlanChangesResponse] OK """ _response = self._client_wrapper.httpx_client.request( - f"plan-traits/{encode_path_param(plan_trait_id)}", + "plan-changes", method="GET", + params={ + "action": action, + "base_plan_action": base_plan_action, + "company_id": company_id, + "company_ids": company_ids, + "limit": limit, + "offset": offset, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - GetPlanTraitResponse, + ListPlanChangesResponse, parse_obj_as( - type_=GetPlanTraitResponse, # type: ignore + type_=ListPlanChangesResponse, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 401: raise UnauthorizedError( headers=dict(_response.headers), @@ -3570,68 +3592,38 @@ def get_plan_trait( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def update_plan_traits_bulk( - self, - *, - apply_to_existing_companies: bool, - plan_id: str, - traits: typing.Sequence[UpdatePlanTraitTraitRequestBody], - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[UpdatePlanTraitsBulkResponse]: + def get_plan_change( + self, plan_change_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[GetPlanChangeResponse]: """ Parameters ---------- - apply_to_existing_companies : bool - - plan_id : str - - traits : typing.Sequence[UpdatePlanTraitTraitRequestBody] + plan_change_id : str + plan_change_id request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[UpdatePlanTraitsBulkResponse] + HttpResponse[GetPlanChangeResponse] OK """ _response = self._client_wrapper.httpx_client.request( - "plan-traits/bulk", - method="POST", - json={ - "apply_to_existing_companies": apply_to_existing_companies, - "plan_id": plan_id, - "traits": convert_and_respect_annotation_metadata( - object_=traits, annotation=typing.Sequence[UpdatePlanTraitTraitRequestBody], direction="write" - ), - }, - headers={ - "content-type": "application/json", - }, + f"plan-changes/{encode_path_param(plan_change_id)}", + method="GET", request_options=request_options, - omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - UpdatePlanTraitsBulkResponse, + GetPlanChangeResponse, parse_obj_as( - type_=UpdatePlanTraitsBulkResponse, # type: ignore + type_=GetPlanChangeResponse, # 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( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) if _response.status_code == 401: raise UnauthorizedError( headers=dict(_response.headers), @@ -3689,7 +3681,7 @@ def update_plan_traits_bulk( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def count_plan_traits( + def list_plan_traits( self, *, ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, @@ -3699,7 +3691,7 @@ def count_plan_traits( limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[CountPlanTraitsResponse]: + ) -> HttpResponse[ListPlanTraitsResponse]: """ Parameters ---------- @@ -3722,11 +3714,11 @@ def count_plan_traits( Returns ------- - HttpResponse[CountPlanTraitsResponse] + HttpResponse[ListPlanTraitsResponse] OK """ _response = self._client_wrapper.httpx_client.request( - "plan-traits/count", + "plan-traits", method="GET", params={ "ids": ids, @@ -3741,9 +3733,9 @@ def count_plan_traits( try: if 200 <= _response.status_code < 300: _data = typing.cast( - CountPlanTraitsResponse, + ListPlanTraitsResponse, parse_obj_as( - type_=CountPlanTraitsResponse, # type: ignore + type_=ListPlanTraitsResponse, # type: ignore object_=_response.json(), ), ) @@ -3816,51 +3808,129 @@ def count_plan_traits( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def upsert_user_trait( + def get_plan_trait( + self, plan_trait_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[GetPlanTraitResponse]: + """ + Parameters + ---------- + plan_trait_id : str + plan_trait_id + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[GetPlanTraitResponse] + OK + """ + _response = self._client_wrapper.httpx_client.request( + f"plan-traits/{encode_path_param(plan_trait_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + GetPlanTraitResponse, + parse_obj_as( + type_=GetPlanTraitResponse, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_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 core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def update_plan_traits_bulk( self, *, - keys: typing.Dict[str, str], - trait: str, - incr: typing.Optional[int] = OMIT, - set_: typing.Optional[str] = OMIT, - update_only: typing.Optional[bool] = OMIT, + apply_to_existing_companies: bool, + plan_id: str, + traits: typing.Sequence[UpdatePlanTraitTraitRequestBody], request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[UpsertUserTraitResponse]: + ) -> HttpResponse[UpdatePlanTraitsBulkResponse]: """ Parameters ---------- - keys : typing.Dict[str, str] - Key/value pairs to identify a company or user - - trait : str - Name of the trait to update - - incr : typing.Optional[int] - Amount to increment the trait by (positive or negative) + apply_to_existing_companies : bool - set_ : typing.Optional[str] - Value to set the trait to + plan_id : str - update_only : typing.Optional[bool] - Unless this is set, the company or user will be created if it does not already exist + traits : typing.Sequence[UpdatePlanTraitTraitRequestBody] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[UpsertUserTraitResponse] + HttpResponse[UpdatePlanTraitsBulkResponse] OK """ _response = self._client_wrapper.httpx_client.request( - "user-traits", + "plan-traits/bulk", method="POST", json={ - "incr": incr, - "keys": keys, - "set": set_, - "trait": trait, - "update_only": update_only, + "apply_to_existing_companies": apply_to_existing_companies, + "plan_id": plan_id, + "traits": convert_and_respect_annotation_metadata( + object_=traits, annotation=typing.Sequence[UpdatePlanTraitTraitRequestBody], direction="write" + ), }, headers={ "content-type": "application/json", @@ -3871,9 +3941,9 @@ def upsert_user_trait( try: if 200 <= _response.status_code < 300: _data = typing.cast( - UpsertUserTraitResponse, + UpdatePlanTraitsBulkResponse, parse_obj_as( - type_=UpsertUserTraitResponse, # type: ignore + type_=UpdatePlanTraitsBulkResponse, # type: ignore object_=_response.json(), ), ) @@ -3946,31 +4016,27 @@ def upsert_user_trait( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def list_users( + def count_plan_traits( self, *, - company_id: typing.Optional[str] = None, ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, plan_id: typing.Optional[str] = None, - q: typing.Optional[str] = None, + trait_id: typing.Optional[str] = None, + trait_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[ListUsersResponse]: + ) -> HttpResponse[CountPlanTraitsResponse]: """ Parameters ---------- - company_id : typing.Optional[str] - Filter users by company ID (starts with comp_) - ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] - Filter users by multiple user IDs (starts with user_) plan_id : typing.Optional[str] - Filter users by plan ID (starts with plan_) - q : typing.Optional[str] - Search for users by name, keys or string traits + trait_id : typing.Optional[str] + + trait_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] limit : typing.Optional[int] Page limit (default 100) @@ -3983,17 +4049,17 @@ def list_users( Returns ------- - HttpResponse[ListUsersResponse] + HttpResponse[CountPlanTraitsResponse] OK """ _response = self._client_wrapper.httpx_client.request( - "users", + "plan-traits/count", method="GET", params={ - "company_id": company_id, "ids": ids, "plan_id": plan_id, - "q": q, + "trait_id": trait_id, + "trait_ids": trait_ids, "limit": limit, "offset": offset, }, @@ -4002,9 +4068,9 @@ def list_users( try: if 200 <= _response.status_code < 300: _data = typing.cast( - ListUsersResponse, + CountPlanTraitsResponse, parse_obj_as( - type_=ListUsersResponse, # type: ignore + type_=CountPlanTraitsResponse, # type: ignore object_=_response.json(), ), ) @@ -4077,72 +4143,50 @@ def list_users( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def upsert_user( + def upsert_user_trait( self, *, keys: typing.Dict[str, str], - companies: typing.Optional[typing.Sequence[typing.Dict[str, str]]] = OMIT, - company: typing.Optional[typing.Dict[str, str]] = OMIT, - company_id: typing.Optional[str] = OMIT, - company_ids: typing.Optional[typing.Sequence[str]] = OMIT, - id: typing.Optional[str] = OMIT, - last_seen_at: typing.Optional[dt.datetime] = OMIT, - name: typing.Optional[str] = OMIT, - traits: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + trait: str, + incr: typing.Optional[int] = OMIT, + set_: typing.Optional[str] = OMIT, update_only: typing.Optional[bool] = OMIT, request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[UpsertUserResponse]: + ) -> HttpResponse[UpsertUserTraitResponse]: """ Parameters ---------- keys : typing.Dict[str, str] - See [Key Management](https://docs.schematichq.com/developer_resources/key_management) for more information + Key/value pairs to identify a company or user - companies : typing.Optional[typing.Sequence[typing.Dict[str, str]]] - Optionally specify companies using array of key/value pairs - - company : typing.Optional[typing.Dict[str, str]] - Add user to this company. Takes priority over companies. For exhaustive list of companies, use companies - - company_id : typing.Optional[str] - Add user to this company. Takes priority over company_ids. For exhaustive list of companies, use company_ids - - company_ids : typing.Optional[typing.Sequence[str]] - Optionally specify companies using Schematic company ID - - id : typing.Optional[str] - If you know the Schematic ID, you can use that here instead of keys - - last_seen_at : typing.Optional[dt.datetime] + trait : str + Name of the trait to update - name : typing.Optional[str] + incr : typing.Optional[int] + Amount to increment the trait by (positive or negative) - traits : typing.Optional[typing.Dict[str, typing.Any]] - A map of trait names to trait values + set_ : typing.Optional[str] + Value to set the trait to update_only : typing.Optional[bool] + Unless this is set, the company or user will be created if it does not already exist request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[UpsertUserResponse] + HttpResponse[UpsertUserTraitResponse] OK """ _response = self._client_wrapper.httpx_client.request( - "users", + "user-traits", method="POST", json={ - "companies": companies, - "company": company, - "company_id": company_id, - "company_ids": company_ids, - "id": id, + "incr": incr, "keys": keys, - "last_seen_at": last_seen_at, - "name": name, - "traits": traits, + "set": set_, + "trait": trait, "update_only": update_only, }, headers={ @@ -4154,9 +4198,9 @@ def upsert_user( try: if 200 <= _response.status_code < 300: _data = typing.cast( - UpsertUserResponse, + UpsertUserTraitResponse, parse_obj_as( - type_=UpsertUserResponse, # type: ignore + type_=UpsertUserTraitResponse, # type: ignore object_=_response.json(), ), ) @@ -4229,38 +4273,80 @@ def upsert_user( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def get_user( - self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[GetUserResponse]: + def list_users( + self, + *, + company_id: typing.Optional[str] = None, + ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + plan_id: typing.Optional[str] = None, + q: typing.Optional[str] = None, + limit: typing.Optional[int] = None, + offset: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ListUsersResponse]: """ Parameters ---------- - user_id : str - user_id + company_id : typing.Optional[str] + Filter users by company ID (starts with comp_) + + ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Filter users by multiple user IDs (starts with user_) + + plan_id : typing.Optional[str] + Filter users by plan ID (starts with plan_) + + q : typing.Optional[str] + Search for users by name, keys or string traits + + limit : typing.Optional[int] + Page limit (default 100) + + offset : typing.Optional[int] + Page offset (default 0) request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[GetUserResponse] + HttpResponse[ListUsersResponse] OK """ _response = self._client_wrapper.httpx_client.request( - f"users/{encode_path_param(user_id)}", + "users", method="GET", + params={ + "company_id": company_id, + "ids": ids, + "plan_id": plan_id, + "q": q, + "limit": limit, + "offset": offset, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - GetUserResponse, + ListUsersResponse, parse_obj_as( - type_=GetUserResponse, # type: ignore + type_=ListUsersResponse, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 401: raise UnauthorizedError( headers=dict(_response.headers), @@ -4318,34 +4404,91 @@ def get_user( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def delete_user( - self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> HttpResponse[DeleteUserResponse]: + def upsert_user( + self, + *, + keys: typing.Dict[str, str], + companies: typing.Optional[typing.Sequence[typing.Dict[str, str]]] = OMIT, + company: typing.Optional[typing.Dict[str, str]] = OMIT, + company_id: typing.Optional[str] = OMIT, + company_ids: typing.Optional[typing.Sequence[str]] = OMIT, + id: typing.Optional[str] = OMIT, + last_seen_at: typing.Optional[dt.datetime] = OMIT, + name: typing.Optional[str] = OMIT, + remove_keys: typing.Optional[typing.Sequence[str]] = OMIT, + traits: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + update_only: typing.Optional[bool] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[UpsertUserResponse]: """ Parameters ---------- - user_id : str - user_id + keys : typing.Dict[str, str] + See [Key Management](https://docs.schematichq.com/developer_resources/key_management) for more information + + companies : typing.Optional[typing.Sequence[typing.Dict[str, str]]] + Optionally specify companies using array of key/value pairs + + company : typing.Optional[typing.Dict[str, str]] + Add user to this company. Takes priority over companies. For exhaustive list of companies, use companies + + company_id : typing.Optional[str] + Add user to this company. Takes priority over company_ids. For exhaustive list of companies, use company_ids + + company_ids : typing.Optional[typing.Sequence[str]] + Optionally specify companies using Schematic company ID + + id : typing.Optional[str] + If you know the Schematic ID, you can use that here instead of keys + + last_seen_at : typing.Optional[dt.datetime] + + name : typing.Optional[str] + + remove_keys : typing.Optional[typing.Sequence[str]] + Names of keys to remove from the user. Removing a key the user does not have does nothing, and a user must keep at least one key. + + traits : typing.Optional[typing.Dict[str, typing.Any]] + A map of trait names to trait values + + update_only : typing.Optional[bool] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[DeleteUserResponse] + HttpResponse[UpsertUserResponse] OK """ _response = self._client_wrapper.httpx_client.request( - f"users/{encode_path_param(user_id)}", - method="DELETE", + "users", + method="POST", + json={ + "companies": companies, + "company": company, + "company_id": company_id, + "company_ids": company_ids, + "id": id, + "keys": keys, + "last_seen_at": last_seen_at, + "name": name, + "remove_keys": remove_keys, + "traits": traits, + "update_only": update_only, + }, + headers={ + "content-type": "application/json", + }, request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - DeleteUserResponse, + UpsertUserResponse, parse_obj_as( - type_=DeleteUserResponse, # type: ignore + type_=UpsertUserResponse, # type: ignore object_=_response.json(), ), ) @@ -4418,80 +4561,38 @@ def delete_user( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def count_users( - self, - *, - company_id: typing.Optional[str] = None, - ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, - plan_id: typing.Optional[str] = None, - q: typing.Optional[str] = None, - limit: typing.Optional[int] = None, - offset: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[CountUsersResponse]: + def get_user( + self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[GetUserResponse]: """ Parameters ---------- - company_id : typing.Optional[str] - Filter users by company ID (starts with comp_) - - ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] - Filter users by multiple user IDs (starts with user_) - - plan_id : typing.Optional[str] - Filter users by plan ID (starts with plan_) - - q : typing.Optional[str] - Search for users by name, keys or string traits - - limit : typing.Optional[int] - Page limit (default 100) - - offset : typing.Optional[int] - Page offset (default 0) + user_id : str + user_id request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - HttpResponse[CountUsersResponse] + HttpResponse[GetUserResponse] OK """ _response = self._client_wrapper.httpx_client.request( - "users/count", + f"users/{encode_path_param(user_id)}", method="GET", - params={ - "company_id": company_id, - "ids": ids, - "plan_id": plan_id, - "q": q, - "limit": limit, - "offset": offset, - }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - CountUsersResponse, + GetUserResponse, parse_obj_as( - type_=CountUsersResponse, # type: ignore + type_=GetUserResponse, # 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( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) if _response.status_code == 401: raise UnauthorizedError( headers=dict(_response.headers), @@ -4549,25 +4650,257 @@ def count_users( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - def create_user( - self, - *, - keys: typing.Dict[str, str], - companies: typing.Optional[typing.Sequence[typing.Dict[str, str]]] = OMIT, - company: typing.Optional[typing.Dict[str, str]] = OMIT, - company_id: typing.Optional[str] = OMIT, - company_ids: typing.Optional[typing.Sequence[str]] = OMIT, - id: typing.Optional[str] = OMIT, - last_seen_at: typing.Optional[dt.datetime] = OMIT, - name: typing.Optional[str] = OMIT, - traits: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, - update_only: typing.Optional[bool] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> HttpResponse[CreateUserResponse]: + def delete_user( + self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[DeleteUserResponse]: """ Parameters ---------- - keys : typing.Dict[str, str] + user_id : str + user_id + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[DeleteUserResponse] + OK + """ + _response = self._client_wrapper.httpx_client.request( + f"users/{encode_path_param(user_id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DeleteUserResponse, + parse_obj_as( + type_=DeleteUserResponse, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_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 core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def count_users( + self, + *, + company_id: typing.Optional[str] = None, + ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + plan_id: typing.Optional[str] = None, + q: typing.Optional[str] = None, + limit: typing.Optional[int] = None, + offset: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[CountUsersResponse]: + """ + Parameters + ---------- + company_id : typing.Optional[str] + Filter users by company ID (starts with comp_) + + ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Filter users by multiple user IDs (starts with user_) + + plan_id : typing.Optional[str] + Filter users by plan ID (starts with plan_) + + q : typing.Optional[str] + Search for users by name, keys or string traits + + limit : typing.Optional[int] + Page limit (default 100) + + offset : typing.Optional[int] + Page offset (default 0) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[CountUsersResponse] + OK + """ + _response = self._client_wrapper.httpx_client.request( + "users/count", + method="GET", + params={ + "company_id": company_id, + "ids": ids, + "plan_id": plan_id, + "q": q, + "limit": limit, + "offset": offset, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + CountUsersResponse, + parse_obj_as( + type_=CountUsersResponse, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_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 core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + def create_user( + self, + *, + keys: typing.Dict[str, str], + companies: typing.Optional[typing.Sequence[typing.Dict[str, str]]] = OMIT, + company: typing.Optional[typing.Dict[str, str]] = OMIT, + company_id: typing.Optional[str] = OMIT, + company_ids: typing.Optional[typing.Sequence[str]] = OMIT, + id: typing.Optional[str] = OMIT, + last_seen_at: typing.Optional[dt.datetime] = OMIT, + name: typing.Optional[str] = OMIT, + remove_keys: typing.Optional[typing.Sequence[str]] = OMIT, + traits: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + update_only: typing.Optional[bool] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[CreateUserResponse]: + """ + Parameters + ---------- + keys : typing.Dict[str, str] See [Key Management](https://docs.schematichq.com/developer_resources/key_management) for more information companies : typing.Optional[typing.Sequence[typing.Dict[str, str]]] @@ -4589,6 +4922,9 @@ def create_user( name : typing.Optional[str] + remove_keys : typing.Optional[typing.Sequence[str]] + Names of keys to remove from the user. Removing a key the user does not have does nothing, and a user must keep at least one key. + traits : typing.Optional[typing.Dict[str, typing.Any]] A map of trait names to trait values @@ -4614,6 +4950,7 @@ def create_user( "keys": keys, "last_seen_at": last_seen_at, "name": name, + "remove_keys": remove_keys, "traits": traits, "update_only": update_only, }, @@ -4915,6 +5252,7 @@ async def list_companies( plan_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, plan_version_id: typing.Optional[str] = None, plan_version_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + plan_version_unpublished: typing.Optional[bool] = None, q: typing.Optional[str] = None, sort_order_column: typing.Optional[str] = None, sort_order_direction: typing.Optional[SortDirection] = None, @@ -4958,6 +5296,9 @@ async def list_companies( plan_version_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] Filter companies by one or more plan version IDs (each ID starts with plvr_). Takes precedence over plan_version_id when set. + plan_version_unpublished : typing.Optional[bool] + Filter companies assigned to a plan version that is no longer published, meaning the plan has since moved on to a newer version + q : typing.Optional[str] Search for companies by name, keys or string traits @@ -5014,6 +5355,7 @@ async def list_companies( "plan_ids": plan_ids, "plan_version_id": plan_version_id, "plan_version_ids": plan_version_ids, + "plan_version_unpublished": plan_version_unpublished, "q": q, "sort_order_column": sort_order_column, "sort_order_direction": sort_order_direction, @@ -5117,6 +5459,7 @@ async def upsert_company( last_seen_at: typing.Optional[dt.datetime] = OMIT, name: typing.Optional[str] = OMIT, prevent_key_remap: typing.Optional[bool] = OMIT, + remove_keys: typing.Optional[typing.Sequence[str]] = OMIT, traits: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, update_only: typing.Optional[bool] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -5142,6 +5485,9 @@ async def upsert_company( prevent_key_remap : typing.Optional[bool] + remove_keys : typing.Optional[typing.Sequence[str]] + Names of keys to remove from the company. Removing a key the company does not have does nothing, and a company must keep at least one key. + traits : typing.Optional[typing.Dict[str, typing.Any]] A map of trait names to trait values @@ -5166,6 +5512,7 @@ async def upsert_company( "last_seen_at": last_seen_at, "name": name, "prevent_key_remap": prevent_key_remap, + "remove_keys": remove_keys, "traits": traits, "update_only": update_only, }, @@ -5466,6 +5813,7 @@ async def count_companies( plan_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, plan_version_id: typing.Optional[str] = None, plan_version_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + plan_version_unpublished: typing.Optional[bool] = None, q: typing.Optional[str] = None, sort_order_column: typing.Optional[str] = None, sort_order_direction: typing.Optional[SortDirection] = None, @@ -5509,6 +5857,9 @@ async def count_companies( plan_version_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] Filter companies by one or more plan version IDs (each ID starts with plvr_). Takes precedence over plan_version_id when set. + plan_version_unpublished : typing.Optional[bool] + Filter companies assigned to a plan version that is no longer published, meaning the plan has since moved on to a newer version + q : typing.Optional[str] Search for companies by name, keys or string traits @@ -5565,6 +5916,7 @@ async def count_companies( "plan_ids": plan_ids, "plan_version_id": plan_version_id, "plan_version_ids": plan_version_ids, + "plan_version_unpublished": plan_version_unpublished, "q": q, "sort_order_column": sort_order_column, "sort_order_direction": sort_order_direction, @@ -5658,80 +6010,391 @@ async def count_companies( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def create_company( - self, - *, - keys: typing.Dict[str, str], - base_plan_id: typing.Optional[str] = OMIT, - base_plan_price_id: typing.Optional[str] = OMIT, - id: typing.Optional[str] = OMIT, - last_seen_at: typing.Optional[dt.datetime] = OMIT, - name: typing.Optional[str] = OMIT, - prevent_key_remap: typing.Optional[bool] = OMIT, - traits: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, - update_only: typing.Optional[bool] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[CreateCompanyResponse]: + async def create_company( + self, + *, + keys: typing.Dict[str, str], + base_plan_id: typing.Optional[str] = OMIT, + base_plan_price_id: typing.Optional[str] = OMIT, + id: typing.Optional[str] = OMIT, + last_seen_at: typing.Optional[dt.datetime] = OMIT, + name: typing.Optional[str] = OMIT, + prevent_key_remap: typing.Optional[bool] = OMIT, + remove_keys: typing.Optional[typing.Sequence[str]] = OMIT, + traits: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + update_only: typing.Optional[bool] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[CreateCompanyResponse]: + """ + Parameters + ---------- + keys : typing.Dict[str, str] + See [Key Management](https://docs.schematichq.com/developer_resources/key_management) for more information + + base_plan_id : typing.Optional[str] + Assign this base plan when creating the company (starts with plan_). Takes precedence over the environment's initial plan and must be provisionable without a payment method. + + base_plan_price_id : typing.Optional[str] + The Schematic price to provision for base_plan_id (starts with bilpp_). Required and must be $0 for a billing-linked plan; omit for a plan that is not billing-linked. + + id : typing.Optional[str] + If you know the Schematic ID, you can use that here instead of keys + + last_seen_at : typing.Optional[dt.datetime] + + name : typing.Optional[str] + + prevent_key_remap : typing.Optional[bool] + + remove_keys : typing.Optional[typing.Sequence[str]] + Names of keys to remove from the company. Removing a key the company does not have does nothing, and a company must keep at least one key. + + traits : typing.Optional[typing.Dict[str, typing.Any]] + A map of trait names to trait values + + update_only : typing.Optional[bool] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[CreateCompanyResponse] + Created + """ + _response = await self._client_wrapper.httpx_client.request( + "companies/create", + method="POST", + json={ + "base_plan_id": base_plan_id, + "base_plan_price_id": base_plan_price_id, + "id": id, + "keys": keys, + "last_seen_at": last_seen_at, + "name": name, + "prevent_key_remap": prevent_key_remap, + "remove_keys": remove_keys, + "traits": traits, + "update_only": update_only, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + CreateCompanyResponse, + parse_obj_as( + type_=CreateCompanyResponse, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_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 core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + async def delete_company_by_keys( + self, *, keys: typing.Dict[str, str], request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[DeleteCompanyByKeysResponse]: + """ + Parameters + ---------- + keys : typing.Dict[str, str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[DeleteCompanyByKeysResponse] + OK + """ + _response = await self._client_wrapper.httpx_client.request( + "companies/delete", + method="POST", + json={ + "keys": keys, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DeleteCompanyByKeysResponse, + parse_obj_as( + type_=DeleteCompanyByKeysResponse, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_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 core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + async def lookup_company( + self, *, keys: typing.Dict[str, str], request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[LookupCompanyResponse]: + """ + Company lookup is determined to resolve a company from its keys, similar to how many of our other apis work. + The following approaches will all work to resolve a company and any of them are appropriate: + 1. `/companies/lookup?keys={"foo": "bar", "fizz": "buzz"}` + 2. `/companies/lookup?keys[foo]=bar&keys[fizz]=buzz` + 2. `/companies/lookup?foo=bar&fizz=buzz` + + Parameters + ---------- + keys : typing.Dict[str, str] + Key/value pairs + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[LookupCompanyResponse] + OK + """ + _response = await self._client_wrapper.httpx_client.request( + "companies/lookup", + method="GET", + params={ + "keys": keys, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + LookupCompanyResponse, + parse_obj_as( + type_=LookupCompanyResponse, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_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 core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + + async def get_company_billing_entity( + self, *, company_id: str, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[GetCompanyBillingEntityResponse]: """ Parameters ---------- - keys : typing.Dict[str, str] - See [Key Management](https://docs.schematichq.com/developer_resources/key_management) for more information - - base_plan_id : typing.Optional[str] - Assign this base plan when creating the company (starts with plan_). Takes precedence over the environment's initial plan and must be provisionable without a payment method. - - base_plan_price_id : typing.Optional[str] - The Schematic price to provision for base_plan_id (starts with bilpp_). Required and must be $0 for a billing-linked plan; omit for a plan that is not billing-linked. - - id : typing.Optional[str] - If you know the Schematic ID, you can use that here instead of keys - - last_seen_at : typing.Optional[dt.datetime] - - name : typing.Optional[str] - - prevent_key_remap : typing.Optional[bool] - - traits : typing.Optional[typing.Dict[str, typing.Any]] - A map of trait names to trait values - - update_only : typing.Optional[bool] + company_id : str request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[CreateCompanyResponse] - Created + AsyncHttpResponse[GetCompanyBillingEntityResponse] + OK """ _response = await self._client_wrapper.httpx_client.request( - "companies/create", - method="POST", - json={ - "base_plan_id": base_plan_id, - "base_plan_price_id": base_plan_price_id, - "id": id, - "keys": keys, - "last_seen_at": last_seen_at, - "name": name, - "prevent_key_remap": prevent_key_remap, - "traits": traits, - "update_only": update_only, - }, - headers={ - "content-type": "application/json", + "company-billing-entity", + method="GET", + params={ + "company_id": company_id, }, request_options=request_options, - omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - CreateCompanyResponse, + GetCompanyBillingEntityResponse, parse_obj_as( - type_=CreateCompanyResponse, # type: ignore + type_=GetCompanyBillingEntityResponse, # type: ignore object_=_response.json(), ), ) @@ -5804,40 +6467,36 @@ async def create_company( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def delete_company_by_keys( - self, *, keys: typing.Dict[str, str], request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[DeleteCompanyByKeysResponse]: + async def get_billing_entity_child_subscriptions( + self, *, company_id: str, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[GetBillingEntityChildSubscriptionsResponse]: """ Parameters ---------- - keys : typing.Dict[str, str] + company_id : str request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[DeleteCompanyByKeysResponse] + AsyncHttpResponse[GetBillingEntityChildSubscriptionsResponse] OK """ _response = await self._client_wrapper.httpx_client.request( - "companies/delete", - method="POST", - json={ - "keys": keys, - }, - headers={ - "content-type": "application/json", + "company-billing-entity-subscriptions", + method="GET", + params={ + "company_id": company_id, }, request_options=request_options, - omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - DeleteCompanyByKeysResponse, + GetBillingEntityChildSubscriptionsResponse, parse_obj_as( - type_=DeleteCompanyByKeysResponse, # type: ignore + type_=GetBillingEntityChildSubscriptionsResponse, # type: ignore object_=_response.json(), ), ) @@ -5910,47 +6569,68 @@ async def delete_company_by_keys( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def lookup_company( - self, *, keys: typing.Dict[str, str], request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[LookupCompanyResponse]: + async def list_company_memberships( + self, + *, + company_id: typing.Optional[str] = None, + user_id: typing.Optional[str] = None, + limit: typing.Optional[int] = None, + offset: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ListCompanyMembershipsResponse]: """ - Company lookup is determined to resolve a company from its keys, similar to how many of our other apis work. - The following approaches will all work to resolve a company and any of them are appropriate: - 1. `/companies/lookup?keys={"foo": "bar", "fizz": "buzz"}` - 2. `/companies/lookup?keys[foo]=bar&keys[fizz]=buzz` - 2. `/companies/lookup?foo=bar&fizz=buzz` - Parameters ---------- - keys : typing.Dict[str, str] - Key/value pairs + company_id : typing.Optional[str] + + user_id : typing.Optional[str] + + limit : typing.Optional[int] + Page limit (default 100) + + offset : typing.Optional[int] + Page offset (default 0) request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[LookupCompanyResponse] + AsyncHttpResponse[ListCompanyMembershipsResponse] OK """ _response = await self._client_wrapper.httpx_client.request( - "companies/lookup", + "company-memberships", method="GET", params={ - "keys": keys, + "company_id": company_id, + "user_id": user_id, + "limit": limit, + "offset": offset, }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - LookupCompanyResponse, + ListCompanyMembershipsResponse, parse_obj_as( - type_=LookupCompanyResponse, # type: ignore + type_=ListCompanyMembershipsResponse, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 401: raise UnauthorizedError( headers=dict(_response.headers), @@ -6008,36 +6688,43 @@ async def lookup_company( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def get_company_billing_entity( - self, *, company_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[GetCompanyBillingEntityResponse]: + async def get_or_create_company_membership( + self, *, company_id: str, user_id: str, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[GetOrCreateCompanyMembershipResponse]: """ Parameters ---------- - company_id : typing.Optional[str] + company_id : str + + user_id : str request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[GetCompanyBillingEntityResponse] + AsyncHttpResponse[GetOrCreateCompanyMembershipResponse] OK """ _response = await self._client_wrapper.httpx_client.request( - "company-billing-entity", - method="GET", - params={ + "company-memberships", + method="POST", + json={ "company_id": company_id, + "user_id": user_id, + }, + headers={ + "content-type": "application/json", }, request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - GetCompanyBillingEntityResponse, + GetOrCreateCompanyMembershipResponse, parse_obj_as( - type_=GetCompanyBillingEntityResponse, # type: ignore + type_=GetOrCreateCompanyMembershipResponse, # type: ignore object_=_response.json(), ), ) @@ -6110,36 +6797,34 @@ async def get_company_billing_entity( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def get_billing_entity_child_subscriptions( - self, *, company_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[GetBillingEntityChildSubscriptionsResponse]: + async def delete_company_membership( + self, company_membership_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[DeleteCompanyMembershipResponse]: """ Parameters ---------- - company_id : typing.Optional[str] + company_membership_id : str + company_membership_id request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[GetBillingEntityChildSubscriptionsResponse] + AsyncHttpResponse[DeleteCompanyMembershipResponse] OK """ _response = await self._client_wrapper.httpx_client.request( - "company-billing-entity-subscriptions", - method="GET", - params={ - "company_id": company_id, - }, + f"company-memberships/{encode_path_param(company_membership_id)}", + method="DELETE", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - GetBillingEntityChildSubscriptionsResponse, + DeleteCompanyMembershipResponse, parse_obj_as( - type_=GetBillingEntityChildSubscriptionsResponse, # type: ignore + type_=DeleteCompanyMembershipResponse, # type: ignore object_=_response.json(), ), ) @@ -6212,21 +6897,21 @@ async def get_billing_entity_child_subscriptions( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def list_company_memberships( + async def get_active_company_subscription( self, *, company_id: typing.Optional[str] = None, - user_id: typing.Optional[str] = None, + company_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[ListCompanyMembershipsResponse]: + ) -> AsyncHttpResponse[GetActiveCompanySubscriptionResponse]: """ Parameters ---------- company_id : typing.Optional[str] - user_id : typing.Optional[str] + company_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] limit : typing.Optional[int] Page limit (default 100) @@ -6239,15 +6924,15 @@ async def list_company_memberships( Returns ------- - AsyncHttpResponse[ListCompanyMembershipsResponse] + AsyncHttpResponse[GetActiveCompanySubscriptionResponse] OK """ _response = await self._client_wrapper.httpx_client.request( - "company-memberships", + "company-subscriptions", method="GET", params={ "company_id": company_id, - "user_id": user_id, + "company_ids": company_ids, "limit": limit, "offset": offset, }, @@ -6256,9 +6941,9 @@ async def list_company_memberships( try: if 200 <= _response.status_code < 300: _data = typing.cast( - ListCompanyMembershipsResponse, + GetActiveCompanySubscriptionResponse, parse_obj_as( - type_=ListCompanyMembershipsResponse, # type: ignore + type_=GetActiveCompanySubscriptionResponse, # type: ignore object_=_response.json(), ), ) @@ -6331,30 +7016,51 @@ async def list_company_memberships( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def get_or_create_company_membership( - self, *, company_id: str, user_id: str, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[GetOrCreateCompanyMembershipResponse]: + async def upsert_company_trait( + self, + *, + keys: typing.Dict[str, str], + trait: str, + incr: typing.Optional[int] = OMIT, + set_: typing.Optional[str] = OMIT, + update_only: typing.Optional[bool] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[UpsertCompanyTraitResponse]: """ Parameters ---------- - company_id : str + keys : typing.Dict[str, str] + Key/value pairs to identify a company or user - user_id : str + trait : str + Name of the trait to update + + incr : typing.Optional[int] + Amount to increment the trait by (positive or negative) + + set_ : typing.Optional[str] + Value to set the trait to + + update_only : typing.Optional[bool] + Unless this is set, the company or user will be created if it does not already exist request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[GetOrCreateCompanyMembershipResponse] + AsyncHttpResponse[UpsertCompanyTraitResponse] OK """ _response = await self._client_wrapper.httpx_client.request( - "company-memberships", + "company-traits", method="POST", json={ - "company_id": company_id, - "user_id": user_id, + "incr": incr, + "keys": keys, + "set": set_, + "trait": trait, + "update_only": update_only, }, headers={ "content-type": "application/json", @@ -6365,9 +7071,9 @@ async def get_or_create_company_membership( try: if 200 <= _response.status_code < 300: _data = typing.cast( - GetOrCreateCompanyMembershipResponse, + UpsertCompanyTraitResponse, parse_obj_as( - type_=GetOrCreateCompanyMembershipResponse, # type: ignore + type_=UpsertCompanyTraitResponse, # type: ignore object_=_response.json(), ), ) @@ -6440,34 +7146,57 @@ async def get_or_create_company_membership( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def delete_company_membership( - self, company_membership_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[DeleteCompanyMembershipResponse]: + async def list_entity_key_definitions( + self, + *, + entity_type: typing.Optional[EntityType] = None, + ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + q: typing.Optional[str] = None, + limit: typing.Optional[int] = None, + offset: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ListEntityKeyDefinitionsResponse]: """ Parameters ---------- - company_membership_id : str - company_membership_id + entity_type : typing.Optional[EntityType] + + ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] + + q : typing.Optional[str] + + limit : typing.Optional[int] + Page limit (default 100) + + offset : typing.Optional[int] + Page offset (default 0) request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[DeleteCompanyMembershipResponse] + AsyncHttpResponse[ListEntityKeyDefinitionsResponse] OK """ _response = await self._client_wrapper.httpx_client.request( - f"company-memberships/{encode_path_param(company_membership_id)}", - method="DELETE", + "entity-key-definitions", + method="GET", + params={ + "entity_type": entity_type, + "ids": ids, + "q": q, + "limit": limit, + "offset": offset, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - DeleteCompanyMembershipResponse, + ListEntityKeyDefinitionsResponse, parse_obj_as( - type_=DeleteCompanyMembershipResponse, # type: ignore + type_=ListEntityKeyDefinitionsResponse, # type: ignore object_=_response.json(), ), ) @@ -6540,53 +7269,34 @@ async def delete_company_membership( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def get_active_company_subscription( - self, - *, - company_id: typing.Optional[str] = None, - company_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, - limit: typing.Optional[int] = None, - offset: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[GetActiveCompanySubscriptionResponse]: + async def delete_entity_key_definition( + self, entity_key_definition_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[DeleteEntityKeyDefinitionResponse]: """ Parameters ---------- - company_id : typing.Optional[str] - - company_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] - - limit : typing.Optional[int] - Page limit (default 100) - - offset : typing.Optional[int] - Page offset (default 0) + entity_key_definition_id : str + entity_key_definition_id request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[GetActiveCompanySubscriptionResponse] + AsyncHttpResponse[DeleteEntityKeyDefinitionResponse] OK """ _response = await self._client_wrapper.httpx_client.request( - "company-subscriptions", - method="GET", - params={ - "company_id": company_id, - "company_ids": company_ids, - "limit": limit, - "offset": offset, - }, + f"entity-key-definitions/{encode_path_param(entity_key_definition_id)}", + method="DELETE", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - GetActiveCompanySubscriptionResponse, + DeleteEntityKeyDefinitionResponse, parse_obj_as( - type_=GetActiveCompanySubscriptionResponse, # type: ignore + type_=DeleteEntityKeyDefinitionResponse, # type: ignore object_=_response.json(), ), ) @@ -6659,64 +7369,57 @@ async def get_active_company_subscription( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def upsert_company_trait( + async def count_entity_key_definitions( self, *, - keys: typing.Dict[str, str], - trait: str, - incr: typing.Optional[int] = OMIT, - set_: typing.Optional[str] = OMIT, - update_only: typing.Optional[bool] = OMIT, + entity_type: typing.Optional[EntityType] = None, + ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + q: typing.Optional[str] = None, + limit: typing.Optional[int] = None, + offset: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[UpsertCompanyTraitResponse]: + ) -> AsyncHttpResponse[CountEntityKeyDefinitionsResponse]: """ Parameters ---------- - keys : typing.Dict[str, str] - Key/value pairs to identify a company or user + entity_type : typing.Optional[EntityType] - trait : str - Name of the trait to update + ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] - incr : typing.Optional[int] - Amount to increment the trait by (positive or negative) + q : typing.Optional[str] - set_ : typing.Optional[str] - Value to set the trait to + limit : typing.Optional[int] + Page limit (default 100) - update_only : typing.Optional[bool] - Unless this is set, the company or user will be created if it does not already exist + offset : typing.Optional[int] + Page offset (default 0) request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[UpsertCompanyTraitResponse] + AsyncHttpResponse[CountEntityKeyDefinitionsResponse] OK """ _response = await self._client_wrapper.httpx_client.request( - "company-traits", - method="POST", - json={ - "incr": incr, - "keys": keys, - "set": set_, - "trait": trait, - "update_only": update_only, - }, - headers={ - "content-type": "application/json", + "entity-key-definitions/count", + method="GET", + params={ + "entity_type": entity_type, + "ids": ids, + "q": q, + "limit": limit, + "offset": offset, }, request_options=request_options, - omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - UpsertCompanyTraitResponse, + CountEntityKeyDefinitionsResponse, parse_obj_as( - type_=UpsertCompanyTraitResponse, # type: ignore + type_=CountEntityKeyDefinitionsResponse, # type: ignore object_=_response.json(), ), ) @@ -6789,24 +7492,21 @@ async def upsert_company_trait( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def list_entity_key_definitions( + async def count_entity_keys( self, *, + definition_id: typing.Optional[str] = None, entity_type: typing.Optional[EntityType] = None, - ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, - q: typing.Optional[str] = None, limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[ListEntityKeyDefinitionsResponse]: + ) -> AsyncHttpResponse[CountEntityKeysResponse]: """ Parameters ---------- - entity_type : typing.Optional[EntityType] - - ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] + definition_id : typing.Optional[str] - q : typing.Optional[str] + entity_type : typing.Optional[EntityType] limit : typing.Optional[int] Page limit (default 100) @@ -6819,16 +7519,15 @@ async def list_entity_key_definitions( Returns ------- - AsyncHttpResponse[ListEntityKeyDefinitionsResponse] + AsyncHttpResponse[CountEntityKeysResponse] OK """ _response = await self._client_wrapper.httpx_client.request( - "entity-key-definitions", + "entity-keys/count", method="GET", params={ + "definition_id": definition_id, "entity_type": entity_type, - "ids": ids, - "q": q, "limit": limit, "offset": offset, }, @@ -6837,9 +7536,9 @@ async def list_entity_key_definitions( try: if 200 <= _response.status_code < 300: _data = typing.cast( - ListEntityKeyDefinitionsResponse, + CountEntityKeysResponse, parse_obj_as( - type_=ListEntityKeyDefinitionsResponse, # type: ignore + type_=CountEntityKeysResponse, # type: ignore object_=_response.json(), ), ) @@ -6912,34 +7611,65 @@ async def list_entity_key_definitions( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def delete_entity_key_definition( - self, entity_key_definition_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[DeleteEntityKeyDefinitionResponse]: + async def list_entity_trait_definitions( + self, + *, + entity_type: typing.Optional[EntityType] = None, + ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + q: typing.Optional[str] = None, + trait_type: typing.Optional[TraitType] = None, + trait_types: typing.Optional[typing.Union[TraitType, typing.Sequence[TraitType]]] = None, + limit: typing.Optional[int] = None, + offset: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ListEntityTraitDefinitionsResponse]: """ Parameters ---------- - entity_key_definition_id : str - entity_key_definition_id + entity_type : typing.Optional[EntityType] + + ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] + + q : typing.Optional[str] + + trait_type : typing.Optional[TraitType] + + trait_types : typing.Optional[typing.Union[TraitType, typing.Sequence[TraitType]]] + + limit : typing.Optional[int] + Page limit (default 100) + + offset : typing.Optional[int] + Page offset (default 0) request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[DeleteEntityKeyDefinitionResponse] + AsyncHttpResponse[ListEntityTraitDefinitionsResponse] OK """ _response = await self._client_wrapper.httpx_client.request( - f"entity-key-definitions/{encode_path_param(entity_key_definition_id)}", - method="DELETE", + "entity-trait-definitions", + method="GET", + params={ + "entity_type": entity_type, + "ids": ids, + "q": q, + "trait_type": trait_type, + "trait_types": trait_types, + "limit": limit, + "offset": offset, + }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - DeleteEntityKeyDefinitionResponse, + ListEntityTraitDefinitionsResponse, parse_obj_as( - type_=DeleteEntityKeyDefinitionResponse, # type: ignore + type_=ListEntityTraitDefinitionsResponse, # type: ignore object_=_response.json(), ), ) @@ -7012,57 +7742,55 @@ async def delete_entity_key_definition( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def count_entity_key_definitions( + async def get_or_create_entity_trait_definition( self, *, - entity_type: typing.Optional[EntityType] = None, - ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, - q: typing.Optional[str] = None, - limit: typing.Optional[int] = None, - offset: typing.Optional[int] = None, + entity_type: EntityType, + hierarchy: typing.Sequence[str], + trait_type: TraitType, + display_name: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[CountEntityKeyDefinitionsResponse]: + ) -> AsyncHttpResponse[GetOrCreateEntityTraitDefinitionResponse]: """ Parameters ---------- - entity_type : typing.Optional[EntityType] - - ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] + entity_type : EntityType - q : typing.Optional[str] + hierarchy : typing.Sequence[str] - limit : typing.Optional[int] - Page limit (default 100) + trait_type : TraitType - offset : typing.Optional[int] - Page offset (default 0) + display_name : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[CountEntityKeyDefinitionsResponse] + AsyncHttpResponse[GetOrCreateEntityTraitDefinitionResponse] OK """ _response = await self._client_wrapper.httpx_client.request( - "entity-key-definitions/count", - method="GET", - params={ + "entity-trait-definitions", + method="POST", + json={ + "display_name": display_name, "entity_type": entity_type, - "ids": ids, - "q": q, - "limit": limit, - "offset": offset, + "hierarchy": hierarchy, + "trait_type": trait_type, + }, + headers={ + "content-type": "application/json", }, request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - CountEntityKeyDefinitionsResponse, + GetOrCreateEntityTraitDefinitionResponse, parse_obj_as( - type_=CountEntityKeyDefinitionsResponse, # type: ignore + type_=GetOrCreateEntityTraitDefinitionResponse, # type: ignore object_=_response.json(), ), ) @@ -7135,68 +7863,38 @@ async def count_entity_key_definitions( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def count_entity_keys( - self, - *, - definition_id: typing.Optional[str] = None, - entity_type: typing.Optional[EntityType] = None, - limit: typing.Optional[int] = None, - offset: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[CountEntityKeysResponse]: + async def get_entity_trait_definition( + self, entity_trait_definition_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[GetEntityTraitDefinitionResponse]: """ Parameters ---------- - definition_id : typing.Optional[str] - - entity_type : typing.Optional[EntityType] - - limit : typing.Optional[int] - Page limit (default 100) - - offset : typing.Optional[int] - Page offset (default 0) + entity_trait_definition_id : str + entity_trait_definition_id request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[CountEntityKeysResponse] + AsyncHttpResponse[GetEntityTraitDefinitionResponse] OK """ _response = await self._client_wrapper.httpx_client.request( - "entity-keys/count", + f"entity-trait-definitions/{encode_path_param(entity_trait_definition_id)}", method="GET", - params={ - "definition_id": definition_id, - "entity_type": entity_type, - "limit": limit, - "offset": offset, - }, request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - CountEntityKeysResponse, + GetEntityTraitDefinitionResponse, parse_obj_as( - type_=CountEntityKeysResponse, # type: ignore + type_=GetEntityTraitDefinitionResponse, # 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( - types_api_error_ApiError, - parse_obj_as( - type_=types_api_error_ApiError, # type: ignore - object_=_response.json(), - ), - ), - ) if _response.status_code == 401: raise UnauthorizedError( headers=dict(_response.headers), @@ -7254,65 +7952,51 @@ async def count_entity_keys( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def list_entity_trait_definitions( + async def update_entity_trait_definition( self, + entity_trait_definition_id: str, *, - entity_type: typing.Optional[EntityType] = None, - ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, - q: typing.Optional[str] = None, - trait_type: typing.Optional[TraitType] = None, - trait_types: typing.Optional[typing.Union[TraitType, typing.Sequence[TraitType]]] = None, - limit: typing.Optional[int] = None, - offset: typing.Optional[int] = None, + trait_type: TraitType, + display_name: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[ListEntityTraitDefinitionsResponse]: + ) -> AsyncHttpResponse[UpdateEntityTraitDefinitionResponse]: """ Parameters ---------- - entity_type : typing.Optional[EntityType] - - ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] - - q : typing.Optional[str] - - trait_type : typing.Optional[TraitType] - - trait_types : typing.Optional[typing.Union[TraitType, typing.Sequence[TraitType]]] + entity_trait_definition_id : str + entity_trait_definition_id - limit : typing.Optional[int] - Page limit (default 100) + trait_type : TraitType - offset : typing.Optional[int] - Page offset (default 0) + display_name : typing.Optional[str] request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[ListEntityTraitDefinitionsResponse] + AsyncHttpResponse[UpdateEntityTraitDefinitionResponse] OK """ _response = await self._client_wrapper.httpx_client.request( - "entity-trait-definitions", - method="GET", - params={ - "entity_type": entity_type, - "ids": ids, - "q": q, + f"entity-trait-definitions/{encode_path_param(entity_trait_definition_id)}", + method="PUT", + json={ + "display_name": display_name, "trait_type": trait_type, - "trait_types": trait_types, - "limit": limit, - "offset": offset, + }, + headers={ + "content-type": "application/json", }, request_options=request_options, + omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - ListEntityTraitDefinitionsResponse, + UpdateEntityTraitDefinitionResponse, parse_obj_as( - type_=ListEntityTraitDefinitionsResponse, # type: ignore + type_=UpdateEntityTraitDefinitionResponse, # type: ignore object_=_response.json(), ), ) @@ -7385,55 +8069,34 @@ async def list_entity_trait_definitions( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def get_or_create_entity_trait_definition( - self, - *, - entity_type: EntityType, - hierarchy: typing.Sequence[str], - trait_type: TraitType, - display_name: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[GetOrCreateEntityTraitDefinitionResponse]: + async def delete_entity_trait_definition( + self, entity_trait_definition_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[DeleteEntityTraitDefinitionResponse]: """ Parameters ---------- - entity_type : EntityType - - hierarchy : typing.Sequence[str] - - trait_type : TraitType - - display_name : typing.Optional[str] + entity_trait_definition_id : str + entity_trait_definition_id request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[GetOrCreateEntityTraitDefinitionResponse] + AsyncHttpResponse[DeleteEntityTraitDefinitionResponse] OK """ _response = await self._client_wrapper.httpx_client.request( - "entity-trait-definitions", - method="POST", - json={ - "display_name": display_name, - "entity_type": entity_type, - "hierarchy": hierarchy, - "trait_type": trait_type, - }, - headers={ - "content-type": "application/json", - }, + f"entity-trait-definitions/{encode_path_param(entity_trait_definition_id)}", + method="DELETE", request_options=request_options, - omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - GetOrCreateEntityTraitDefinitionResponse, + DeleteEntityTraitDefinitionResponse, parse_obj_as( - type_=GetOrCreateEntityTraitDefinitionResponse, # type: ignore + type_=DeleteEntityTraitDefinitionResponse, # type: ignore object_=_response.json(), ), ) @@ -7506,9 +8169,9 @@ async def get_or_create_entity_trait_definition( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def get_entity_trait_definition( + async def get_entity_trait_definition_usage( self, entity_trait_definition_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AsyncHttpResponse[GetEntityTraitDefinitionResponse]: + ) -> AsyncHttpResponse[GetEntityTraitDefinitionUsageResponse]: """ Parameters ---------- @@ -7520,20 +8183,20 @@ async def get_entity_trait_definition( Returns ------- - AsyncHttpResponse[GetEntityTraitDefinitionResponse] + AsyncHttpResponse[GetEntityTraitDefinitionUsageResponse] OK """ _response = await self._client_wrapper.httpx_client.request( - f"entity-trait-definitions/{encode_path_param(entity_trait_definition_id)}", + f"entity-trait-definitions/{encode_path_param(entity_trait_definition_id)}/usage", method="GET", request_options=request_options, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - GetEntityTraitDefinitionResponse, + GetEntityTraitDefinitionUsageResponse, parse_obj_as( - type_=GetEntityTraitDefinitionResponse, # type: ignore + type_=GetEntityTraitDefinitionUsageResponse, # type: ignore object_=_response.json(), ), ) @@ -7595,51 +8258,65 @@ async def get_entity_trait_definition( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def update_entity_trait_definition( + async def count_entity_trait_definitions( self, - entity_trait_definition_id: str, *, - trait_type: TraitType, - display_name: typing.Optional[str] = OMIT, + entity_type: typing.Optional[EntityType] = None, + ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + q: typing.Optional[str] = None, + trait_type: typing.Optional[TraitType] = None, + trait_types: typing.Optional[typing.Union[TraitType, typing.Sequence[TraitType]]] = None, + limit: typing.Optional[int] = None, + offset: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[UpdateEntityTraitDefinitionResponse]: + ) -> AsyncHttpResponse[CountEntityTraitDefinitionsResponse]: """ Parameters ---------- - entity_trait_definition_id : str - entity_trait_definition_id + entity_type : typing.Optional[EntityType] - trait_type : TraitType + ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] - display_name : typing.Optional[str] + q : typing.Optional[str] + + trait_type : typing.Optional[TraitType] + + trait_types : typing.Optional[typing.Union[TraitType, typing.Sequence[TraitType]]] + + limit : typing.Optional[int] + Page limit (default 100) + + offset : typing.Optional[int] + Page offset (default 0) request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - AsyncHttpResponse[UpdateEntityTraitDefinitionResponse] + AsyncHttpResponse[CountEntityTraitDefinitionsResponse] OK """ _response = await self._client_wrapper.httpx_client.request( - f"entity-trait-definitions/{encode_path_param(entity_trait_definition_id)}", - method="PUT", - json={ - "display_name": display_name, + "entity-trait-definitions/count", + method="GET", + params={ + "entity_type": entity_type, + "ids": ids, + "q": q, "trait_type": trait_type, - }, - headers={ - "content-type": "application/json", + "trait_types": trait_types, + "limit": limit, + "offset": offset, }, request_options=request_options, - omit=OMIT, ) try: if 200 <= _response.status_code < 300: _data = typing.cast( - UpdateEntityTraitDefinitionResponse, + CountEntityTraitDefinitionsResponse, parse_obj_as( - type_=UpdateEntityTraitDefinitionResponse, # type: ignore + type_=CountEntityTraitDefinitionsResponse, # type: ignore object_=_response.json(), ), ) @@ -7712,31 +8389,22 @@ async def update_entity_trait_definition( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def count_entity_trait_definitions( + async def get_entity_trait_values( self, *, - entity_type: typing.Optional[EntityType] = None, - ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + definition_id: str, q: typing.Optional[str] = None, - trait_type: typing.Optional[TraitType] = None, - trait_types: typing.Optional[typing.Union[TraitType, typing.Sequence[TraitType]]] = None, limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[CountEntityTraitDefinitionsResponse]: + ) -> AsyncHttpResponse[GetEntityTraitValuesResponse]: """ Parameters ---------- - entity_type : typing.Optional[EntityType] - - ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] + definition_id : str q : typing.Optional[str] - trait_type : typing.Optional[TraitType] - - trait_types : typing.Optional[typing.Union[TraitType, typing.Sequence[TraitType]]] - limit : typing.Optional[int] Page limit (default 100) @@ -7748,18 +8416,15 @@ async def count_entity_trait_definitions( Returns ------- - AsyncHttpResponse[CountEntityTraitDefinitionsResponse] + AsyncHttpResponse[GetEntityTraitValuesResponse] OK """ _response = await self._client_wrapper.httpx_client.request( - "entity-trait-definitions/count", + "entity-trait-values", method="GET", params={ - "entity_type": entity_type, - "ids": ids, + "definition_id": definition_id, "q": q, - "trait_type": trait_type, - "trait_types": trait_types, "limit": limit, "offset": offset, }, @@ -7768,9 +8433,9 @@ async def count_entity_trait_definitions( try: if 200 <= _response.status_code < 300: _data = typing.cast( - CountEntityTraitDefinitionsResponse, + GetEntityTraitValuesResponse, parse_obj_as( - type_=CountEntityTraitDefinitionsResponse, # type: ignore + type_=GetEntityTraitValuesResponse, # type: ignore object_=_response.json(), ), ) @@ -7843,21 +8508,21 @@ async def count_entity_trait_definitions( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) - async def get_entity_trait_values( + async def count_entity_traits( self, *, - definition_id: str, - q: typing.Optional[str] = None, + definition_id: typing.Optional[str] = None, + entity_type: typing.Optional[EntityType] = None, limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncHttpResponse[GetEntityTraitValuesResponse]: + ) -> AsyncHttpResponse[CountEntityTraitsResponse]: """ Parameters ---------- - definition_id : str + definition_id : typing.Optional[str] - q : typing.Optional[str] + entity_type : typing.Optional[EntityType] limit : typing.Optional[int] Page limit (default 100) @@ -7870,15 +8535,15 @@ async def get_entity_trait_values( Returns ------- - AsyncHttpResponse[GetEntityTraitValuesResponse] + AsyncHttpResponse[CountEntityTraitsResponse] OK """ _response = await self._client_wrapper.httpx_client.request( - "entity-trait-values", + "entity-traits/count", method="GET", params={ "definition_id": definition_id, - "q": q, + "entity_type": entity_type, "limit": limit, "offset": offset, }, @@ -7887,9 +8552,9 @@ async def get_entity_trait_values( try: if 200 <= _response.status_code < 300: _data = typing.cast( - GetEntityTraitValuesResponse, + CountEntityTraitsResponse, parse_obj_as( - type_=GetEntityTraitValuesResponse, # type: ignore + type_=CountEntityTraitsResponse, # type: ignore object_=_response.json(), ), ) @@ -7969,7 +8634,6 @@ async def list_plan_changes( base_plan_action: typing.Optional[PlanChangeBasePlanAction] = None, company_id: typing.Optional[str] = None, company_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, - plan_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None, @@ -7985,8 +8649,6 @@ async def list_plan_changes( company_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] - plan_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] - limit : typing.Optional[int] Page limit (default 100) @@ -8009,7 +8671,6 @@ async def list_plan_changes( "base_plan_action": base_plan_action, "company_id": company_id, "company_ids": company_ids, - "plan_ids": plan_ids, "limit": limit, "offset": offset, }, @@ -8916,6 +9577,7 @@ async def upsert_user( id: typing.Optional[str] = OMIT, last_seen_at: typing.Optional[dt.datetime] = OMIT, name: typing.Optional[str] = OMIT, + remove_keys: typing.Optional[typing.Sequence[str]] = OMIT, traits: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, update_only: typing.Optional[bool] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -8945,6 +9607,9 @@ async def upsert_user( name : typing.Optional[str] + remove_keys : typing.Optional[typing.Sequence[str]] + Names of keys to remove from the user. Removing a key the user does not have does nothing, and a user must keep at least one key. + traits : typing.Optional[typing.Dict[str, typing.Any]] A map of trait names to trait values @@ -8970,6 +9635,7 @@ async def upsert_user( "keys": keys, "last_seen_at": last_seen_at, "name": name, + "remove_keys": remove_keys, "traits": traits, "update_only": update_only, }, @@ -9388,6 +10054,7 @@ async def create_user( id: typing.Optional[str] = OMIT, last_seen_at: typing.Optional[dt.datetime] = OMIT, name: typing.Optional[str] = OMIT, + remove_keys: typing.Optional[typing.Sequence[str]] = OMIT, traits: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, update_only: typing.Optional[bool] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -9417,6 +10084,9 @@ async def create_user( name : typing.Optional[str] + remove_keys : typing.Optional[typing.Sequence[str]] + Names of keys to remove from the user. Removing a key the user does not have does nothing, and a user must keep at least one key. + traits : typing.Optional[typing.Dict[str, typing.Any]] A map of trait names to trait values @@ -9442,6 +10112,7 @@ async def create_user( "keys": keys, "last_seen_at": last_seen_at, "name": name, + "remove_keys": remove_keys, "traits": traits, "update_only": update_only, }, diff --git a/src/schematic/companies/types/__init__.py b/src/schematic/companies/types/__init__.py index a5e305f..79a8ca1 100644 --- a/src/schematic/companies/types/__init__.py +++ b/src/schematic/companies/types/__init__.py @@ -14,6 +14,8 @@ from .count_entity_keys_response import CountEntityKeysResponse from .count_entity_trait_definitions_params import CountEntityTraitDefinitionsParams from .count_entity_trait_definitions_response import CountEntityTraitDefinitionsResponse + from .count_entity_traits_params import CountEntityTraitsParams + from .count_entity_traits_response import CountEntityTraitsResponse from .count_plan_traits_params import CountPlanTraitsParams from .count_plan_traits_response import CountPlanTraitsResponse from .count_users_params import CountUsersParams @@ -25,6 +27,7 @@ from .delete_company_params import DeleteCompanyParams from .delete_company_response import DeleteCompanyResponse from .delete_entity_key_definition_response import DeleteEntityKeyDefinitionResponse + from .delete_entity_trait_definition_response import DeleteEntityTraitDefinitionResponse from .delete_user_by_keys_response import DeleteUserByKeysResponse from .delete_user_response import DeleteUserResponse from .get_active_company_subscription_params import GetActiveCompanySubscriptionParams @@ -35,6 +38,7 @@ from .get_company_billing_entity_response import GetCompanyBillingEntityResponse from .get_company_response import GetCompanyResponse from .get_entity_trait_definition_response import GetEntityTraitDefinitionResponse + from .get_entity_trait_definition_usage_response import GetEntityTraitDefinitionUsageResponse from .get_entity_trait_values_params import GetEntityTraitValuesParams from .get_entity_trait_values_response import GetEntityTraitValuesResponse from .get_or_create_company_membership_response import GetOrCreateCompanyMembershipResponse @@ -75,6 +79,8 @@ "CountEntityKeysResponse": ".count_entity_keys_response", "CountEntityTraitDefinitionsParams": ".count_entity_trait_definitions_params", "CountEntityTraitDefinitionsResponse": ".count_entity_trait_definitions_response", + "CountEntityTraitsParams": ".count_entity_traits_params", + "CountEntityTraitsResponse": ".count_entity_traits_response", "CountPlanTraitsParams": ".count_plan_traits_params", "CountPlanTraitsResponse": ".count_plan_traits_response", "CountUsersParams": ".count_users_params", @@ -86,6 +92,7 @@ "DeleteCompanyParams": ".delete_company_params", "DeleteCompanyResponse": ".delete_company_response", "DeleteEntityKeyDefinitionResponse": ".delete_entity_key_definition_response", + "DeleteEntityTraitDefinitionResponse": ".delete_entity_trait_definition_response", "DeleteUserByKeysResponse": ".delete_user_by_keys_response", "DeleteUserResponse": ".delete_user_response", "GetActiveCompanySubscriptionParams": ".get_active_company_subscription_params", @@ -96,6 +103,7 @@ "GetCompanyBillingEntityResponse": ".get_company_billing_entity_response", "GetCompanyResponse": ".get_company_response", "GetEntityTraitDefinitionResponse": ".get_entity_trait_definition_response", + "GetEntityTraitDefinitionUsageResponse": ".get_entity_trait_definition_usage_response", "GetEntityTraitValuesParams": ".get_entity_trait_values_params", "GetEntityTraitValuesResponse": ".get_entity_trait_values_response", "GetOrCreateCompanyMembershipResponse": ".get_or_create_company_membership_response", @@ -160,6 +168,8 @@ def __dir__(): "CountEntityKeysResponse", "CountEntityTraitDefinitionsParams", "CountEntityTraitDefinitionsResponse", + "CountEntityTraitsParams", + "CountEntityTraitsResponse", "CountPlanTraitsParams", "CountPlanTraitsResponse", "CountUsersParams", @@ -171,6 +181,7 @@ def __dir__(): "DeleteCompanyParams", "DeleteCompanyResponse", "DeleteEntityKeyDefinitionResponse", + "DeleteEntityTraitDefinitionResponse", "DeleteUserByKeysResponse", "DeleteUserResponse", "GetActiveCompanySubscriptionParams", @@ -181,6 +192,7 @@ def __dir__(): "GetCompanyBillingEntityResponse", "GetCompanyResponse", "GetEntityTraitDefinitionResponse", + "GetEntityTraitDefinitionUsageResponse", "GetEntityTraitValuesParams", "GetEntityTraitValuesResponse", "GetOrCreateCompanyMembershipResponse", diff --git a/src/schematic/companies/types/count_companies_params.py b/src/schematic/companies/types/count_companies_params.py index 8a38f08..477186f 100644 --- a/src/schematic/companies/types/count_companies_params.py +++ b/src/schematic/companies/types/count_companies_params.py @@ -64,6 +64,11 @@ class CountCompaniesParams(UniversalBaseModel): Filter companies by one or more plan version IDs (each ID starts with plvr_). Takes precedence over plan_version_id when set. """ + plan_version_unpublished: typing.Optional[bool] = pydantic.Field(default=None) + """ + Filter companies assigned to a plan version that is no longer published, meaning the plan has since moved on to a newer version + """ + q: typing.Optional[str] = pydantic.Field(default=None) """ Search for companies by name, keys or string traits diff --git a/src/schematic/companies/types/count_entity_traits_params.py b/src/schematic/companies/types/count_entity_traits_params.py new file mode 100644 index 0000000..74df89e --- /dev/null +++ b/src/schematic/companies/types/count_entity_traits_params.py @@ -0,0 +1,34 @@ +# 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.entity_type import EntityType + + +class CountEntityTraitsParams(UniversalBaseModel): + """ + Input parameters + """ + + definition_id: typing.Optional[str] = None + entity_type: typing.Optional[EntityType] = None + limit: typing.Optional[int] = pydantic.Field(default=None) + """ + Page limit (default 100) + """ + + offset: typing.Optional[int] = pydantic.Field(default=None) + """ + Page offset (default 0) + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/schematic/companies/types/count_entity_traits_response.py b/src/schematic/companies/types/count_entity_traits_response.py new file mode 100644 index 0000000..eafe23e --- /dev/null +++ b/src/schematic/companies/types/count_entity_traits_response.py @@ -0,0 +1,25 @@ +# 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.count_response import CountResponse +from .count_entity_traits_params import CountEntityTraitsParams + + +class CountEntityTraitsResponse(UniversalBaseModel): + data: CountResponse + params: CountEntityTraitsParams = pydantic.Field() + """ + Input parameters + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/schematic/companies/types/delete_entity_trait_definition_response.py b/src/schematic/companies/types/delete_entity_trait_definition_response.py new file mode 100644 index 0000000..fae6a65 --- /dev/null +++ b/src/schematic/companies/types/delete_entity_trait_definition_response.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 ...types.delete_response import DeleteResponse + + +class DeleteEntityTraitDefinitionResponse(UniversalBaseModel): + data: DeleteResponse + params: typing.Dict[str, typing.Any] = pydantic.Field() + """ + Input parameters + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/schematic/companies/types/get_entity_trait_definition_usage_response.py b/src/schematic/companies/types/get_entity_trait_definition_usage_response.py new file mode 100644 index 0000000..fc96066 --- /dev/null +++ b/src/schematic/companies/types/get_entity_trait_definition_usage_response.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 ...types.entity_trait_definition_usage import EntityTraitDefinitionUsage + + +class GetEntityTraitDefinitionUsageResponse(UniversalBaseModel): + data: EntityTraitDefinitionUsage + params: typing.Dict[str, typing.Any] = pydantic.Field() + """ + Input parameters + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/schematic/companies/types/list_companies_params.py b/src/schematic/companies/types/list_companies_params.py index 3693cde..e44ff7e 100644 --- a/src/schematic/companies/types/list_companies_params.py +++ b/src/schematic/companies/types/list_companies_params.py @@ -64,6 +64,11 @@ class ListCompaniesParams(UniversalBaseModel): Filter companies by one or more plan version IDs (each ID starts with plvr_). Takes precedence over plan_version_id when set. """ + plan_version_unpublished: typing.Optional[bool] = pydantic.Field(default=None) + """ + Filter companies assigned to a plan version that is no longer published, meaning the plan has since moved on to a newer version + """ + q: typing.Optional[str] = pydantic.Field(default=None) """ Search for companies by name, keys or string traits diff --git a/src/schematic/companies/types/list_plan_changes_params.py b/src/schematic/companies/types/list_plan_changes_params.py index dad497a..04f38e3 100644 --- a/src/schematic/companies/types/list_plan_changes_params.py +++ b/src/schematic/companies/types/list_plan_changes_params.py @@ -27,8 +27,6 @@ class ListPlanChangesParams(UniversalBaseModel): Page offset (default 0) """ - plan_ids: typing.Optional[typing.List[str]] = None - if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 else: diff --git a/src/schematic/core/client_wrapper.py b/src/schematic/core/client_wrapper.py index aa41bb8..c9f76dc 100644 --- a/src/schematic/core/client_wrapper.py +++ b/src/schematic/core/client_wrapper.py @@ -16,6 +16,8 @@ def __init__( base_url: str, timeout: typing.Optional[float] = None, max_retries: int = 2, + stream_reconnection_enabled: typing.Optional[bool] = None, + max_stream_reconnection_attempts: typing.Optional[int] = None, logging: typing.Optional[typing.Union[LogConfig, Logger]] = None, ): self.api_key = api_key @@ -23,18 +25,20 @@ def __init__( self._base_url = base_url self._timeout = timeout self._max_retries = max_retries + self._stream_reconnection_enabled = stream_reconnection_enabled + self._max_stream_reconnection_attempts = max_stream_reconnection_attempts self._logging = logging def get_headers(self) -> typing.Dict[str, str]: import platform headers: typing.Dict[str, str] = { - "User-Agent": "schematichq/1.3.3", + "User-Agent": "schematichq/1.3.4", "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": "schematichq", - "X-Fern-SDK-Version": "1.3.3", + "X-Fern-SDK-Version": "1.3.4", **(self.get_custom_headers() or {}), } headers["X-Schematic-Api-Key"] = self.api_key @@ -52,6 +56,12 @@ def get_timeout(self) -> typing.Optional[float]: def get_max_retries(self) -> int: return self._max_retries + def get_stream_reconnection_enabled(self) -> bool: + return self._stream_reconnection_enabled if self._stream_reconnection_enabled is not None else True + + def get_max_stream_reconnection_attempts(self) -> typing.Optional[int]: + return self._max_stream_reconnection_attempts + class SyncClientWrapper(BaseClientWrapper): def __init__( @@ -62,6 +72,8 @@ def __init__( base_url: str, timeout: typing.Optional[float] = None, max_retries: int = 2, + stream_reconnection_enabled: typing.Optional[bool] = None, + max_stream_reconnection_attempts: typing.Optional[int] = None, logging: typing.Optional[typing.Union[LogConfig, Logger]] = None, httpx_client: httpx.Client, ): @@ -71,6 +83,8 @@ def __init__( base_url=base_url, timeout=timeout, max_retries=max_retries, + stream_reconnection_enabled=stream_reconnection_enabled, + max_stream_reconnection_attempts=max_stream_reconnection_attempts, logging=logging, ) self.httpx_client = HttpClient( @@ -92,6 +106,8 @@ def __init__( base_url: str, timeout: typing.Optional[float] = None, max_retries: int = 2, + stream_reconnection_enabled: typing.Optional[bool] = None, + max_stream_reconnection_attempts: typing.Optional[int] = None, logging: typing.Optional[typing.Union[LogConfig, Logger]] = None, async_token: typing.Optional[typing.Callable[[], typing.Awaitable[str]]] = None, httpx_client: httpx.AsyncClient, @@ -102,6 +118,8 @@ def __init__( base_url=base_url, timeout=timeout, max_retries=max_retries, + stream_reconnection_enabled=stream_reconnection_enabled, + max_stream_reconnection_attempts=max_stream_reconnection_attempts, logging=logging, ) self._async_token = async_token diff --git a/src/schematic/core/http_client.py b/src/schematic/core/http_client.py index f686c57..3e5a786 100644 --- a/src/schematic/core/http_client.py +++ b/src/schematic/core/http_client.py @@ -3,6 +3,7 @@ import asyncio import email.utils import re +import socket import time import typing from contextlib import asynccontextmanager, contextmanager @@ -23,6 +24,39 @@ JITTER_FACTOR = 0.2 # 20% random jitter +def get_keepalive_socket_options( + idle: int = 60, + intvl: int = 30, + cnt: int = 5, +) -> typing.List[typing.Tuple[int, int, int]]: + """ + Build TCP keepalive socket options for the current platform. + + Keepalive probes keep otherwise-idle connections alive so that long, + non-streaming requests survive idle-connection reaping by a firewall, + load balancer, or NAT. The available socket constants are OS-dependent, + so each option is guarded and only emitted when the platform defines it: + + - ``SO_KEEPALIVE`` is portable (Linux/macOS/Windows). + - The idle-before-first-probe knob is ``TCP_KEEPIDLE`` on Linux and modern + Windows, but ``TCP_KEEPALIVE`` on macOS. + - ``TCP_KEEPINTVL`` / ``TCP_KEEPCNT`` exist on Linux/macOS/modern Windows. + + Passing these tuples to ``httpx.HTTPTransport(socket_options=...)`` / + ``httpx.AsyncHTTPTransport(socket_options=...)`` applies them to every + connection the transport opens. + """ + opts: typing.List[typing.Tuple[int, int, int]] = [(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)] + idle_const = getattr(socket, "TCP_KEEPIDLE", None) or getattr(socket, "TCP_KEEPALIVE", None) + if idle_const: + opts.append((socket.IPPROTO_TCP, idle_const, idle)) + if hasattr(socket, "TCP_KEEPINTVL"): + opts.append((socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, intvl)) + if hasattr(socket, "TCP_KEEPCNT"): + opts.append((socket.IPPROTO_TCP, socket.TCP_KEEPCNT, cnt)) + return opts + + 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. @@ -238,7 +272,16 @@ def get_request_body( data: typing.Optional[typing.Any], request_options: typing.Optional[RequestOptions], omit: typing.Optional[typing.Any], + optional_body: bool = False, ) -> typing.Tuple[typing.Optional[typing.Any], typing.Optional[typing.Any]]: + # A whole body left at the sentinel was never passed by the caller, so it is absent + # rather than empty: the request carries no content and no `Content-Type`. + if omit is not None: + if json is omit: + json = None + if data is omit: + data = None + json_body = None data_body = None if data is not None: @@ -254,14 +297,36 @@ def get_request_body( # 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: + # `optional_body` marks an endpoint whose body the API does not require, where a body + # that ends up empty means the caller passed none of its properties, so the request is + # sent with no content and no `Content-Type`. + if json_body == {} and (json is None or optional_body) and not has_additional_body_parameters: json_body = None - if data_body == {} and data is None and not has_additional_body_parameters: + if data_body == {} and (data is None or optional_body) and not has_additional_body_parameters: data_body = None return json_body, data_body +def drop_content_type_without_body( + headers: typing.Dict[str, typing.Any], + *, + json_body: typing.Optional[typing.Any], + data_body: typing.Optional[typing.Any], + optional_body: bool, +) -> typing.Dict[str, typing.Any]: + """Strip ``Content-Type`` from a request that carries no body. + + ``get_request_body`` drops the body of an ``optional_body`` endpoint when the caller + supplied none of it, but the endpoint still passes the content type it would have used. + A request that sends nothing must not advertise a media type, so a server that branches + on the header sees a bodyless call for what it is. + """ + if not optional_body or json_body is not None or data_body is not None: + return headers + return {key: value for key, value in headers.items() if key.lower() != "content-type"} + + class HttpClient: def __init__( self, @@ -309,16 +374,22 @@ def request( request_options: typing.Optional[RequestOptions] = None, retries: int = 0, omit: typing.Optional[typing.Any] = None, + optional_body: bool = False, force_multipart: typing.Optional[bool] = None, ) -> httpx.Response: base_url = self.get_base_url(base_url) - timeout = ( - request_options.get("timeout_in_seconds") + _timeout = ( + request_options.get("timeout") + if request_options is not None and request_options.get("timeout") is not None + else 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() ) + timeout = _timeout if _timeout is not None else httpx.USE_CLIENT_DEFAULT - json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit) + json_body, data_body = get_request_body( + json=json, data=data, request_options=request_options, omit=omit, optional_body=optional_body + ) request_files: typing.Optional[RequestFiles] = ( convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit)) @@ -361,6 +432,9 @@ def request( } ) ) + _request_headers = drop_content_type_without_body( + _request_headers, json_body=json_body, data_body=data_body, optional_body=optional_body + ) if self.logger.is_debug(): self.logger.debug( @@ -469,14 +543,18 @@ def stream( request_options: typing.Optional[RequestOptions] = None, retries: int = 0, omit: typing.Optional[typing.Any] = None, + optional_body: bool = False, 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") + _timeout = ( + request_options.get("timeout") + if request_options is not None and request_options.get("timeout") is not None + else 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() ) + timeout = _timeout if _timeout is not None else httpx.USE_CLIENT_DEFAULT request_files: typing.Optional[RequestFiles] = ( convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit)) @@ -487,7 +565,9 @@ def stream( 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) + json_body, data_body = get_request_body( + json=json, data=data, request_options=request_options, omit=omit, optional_body=optional_body + ) data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart) @@ -521,6 +601,9 @@ def stream( } ) ) + _request_headers = drop_content_type_without_body( + _request_headers, json_body=json_body, data_body=data_body, optional_body=optional_body + ) if self.logger.is_debug(): self.logger.debug( @@ -598,14 +681,18 @@ async def request( request_options: typing.Optional[RequestOptions] = None, retries: int = 0, omit: typing.Optional[typing.Any] = None, + optional_body: bool = False, force_multipart: typing.Optional[bool] = None, ) -> httpx.Response: base_url = self.get_base_url(base_url) - timeout = ( - request_options.get("timeout_in_seconds") + _timeout = ( + request_options.get("timeout") + if request_options is not None and request_options.get("timeout") is not None + else 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() ) + timeout = _timeout if _timeout is not None else httpx.USE_CLIENT_DEFAULT request_files: typing.Optional[RequestFiles] = ( convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit)) @@ -616,7 +703,9 @@ async def request( 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) + json_body, data_body = get_request_body( + json=json, data=data, request_options=request_options, omit=omit, optional_body=optional_body + ) data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart) @@ -653,6 +742,9 @@ async def request( } ) ) + _request_headers = drop_content_type_without_body( + _request_headers, json_body=json_body, data_body=data_body, optional_body=optional_body + ) if self.logger.is_debug(): self.logger.debug( @@ -761,14 +853,18 @@ async def stream( request_options: typing.Optional[RequestOptions] = None, retries: int = 0, omit: typing.Optional[typing.Any] = None, + optional_body: bool = False, 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") + _timeout = ( + request_options.get("timeout") + if request_options is not None and request_options.get("timeout") is not None + else 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() ) + timeout = _timeout if _timeout is not None else httpx.USE_CLIENT_DEFAULT request_files: typing.Optional[RequestFiles] = ( convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit)) @@ -779,7 +875,9 @@ async def stream( 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) + json_body, data_body = get_request_body( + json=json, data=data, request_options=request_options, omit=omit, optional_body=optional_body + ) data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart) @@ -816,6 +914,9 @@ async def stream( } ) ) + _request_headers = drop_content_type_without_body( + _request_headers, json_body=json_body, data_body=data_body, optional_body=optional_body + ) if self.logger.is_debug(): self.logger.debug( diff --git a/src/schematic/core/http_response.py b/src/schematic/core/http_response.py index 00bb109..9aa1e18 100644 --- a/src/schematic/core/http_response.py +++ b/src/schematic/core/http_response.py @@ -24,6 +24,10 @@ def headers(self) -> Dict[str, str]: def status_code(self) -> int: return self._response.status_code + @property + def response(self) -> httpx.Response: + return self._response + class HttpResponse(Generic[T], BaseHttpResponse): """HTTP response wrapper that exposes response headers and data.""" diff --git a/src/schematic/core/http_sse/_api.py b/src/schematic/core/http_sse/_api.py index fd13730..9ca5602 100644 --- a/src/schematic/core/http_sse/_api.py +++ b/src/schematic/core/http_sse/_api.py @@ -2,9 +2,20 @@ import codecs import re +import time from contextlib import asynccontextmanager, contextmanager -from typing import Any, AsyncGenerator, AsyncIterator, Iterator - +from typing import ( + Any, + AsyncContextManager, + AsyncGenerator, + AsyncIterator, + Callable, + ContextManager, + Iterator, + Optional, +) + +import anyio import httpx from ._decoders import SSEDecoder from ._exceptions import SSEError @@ -12,21 +23,60 @@ MAX_LINE_SIZE: int = 1_048_576 # 1 MiB +# Reconnection defaults, mirroring the TypeScript SDK's Stream implementation. +DEFAULT_MAX_RECONNECTION_ATTEMPTS: int = 5 +DEFAULT_RECONNECT_DELAY_MS: int = 1_000 +MAX_RECONNECT_DELAY_MS: int = 30_000 + +# A reconnect callback re-issues the original request (with a ``Last-Event-ID`` +# header set to the supplied event id) and returns a *context manager* yielding +# a fresh streaming ``httpx.Response``. Sync clients supply a sync context +# manager; async clients supply an async one. class EventSource: - def __init__(self, response: httpx.Response) -> None: + def __init__( + self, + response: httpx.Response, + *, + resumable: bool = False, + stream_reconnection_enabled: bool = True, + max_stream_reconnection_attempts: Optional[int] = None, + stream_terminator: Optional[str] = None, + reconnect: Optional[Callable[[str], Any]] = None, + ) -> None: self._response = response + self._resumable = resumable + self._stream_reconnection_enabled = stream_reconnection_enabled + self._max_stream_reconnection_attempts = max_stream_reconnection_attempts + self._stream_terminator = stream_terminator + self._reconnect = reconnect + + @staticmethod + def _is_event_stream(response: httpx.Response) -> bool: + content_type = response.headers.get("content-type", "").partition(";")[0] + return "text/event-stream" in content_type def _check_content_type(self) -> None: - content_type = self._response.headers.get("content-type", "").partition(";")[0] - if "text/event-stream" not in content_type: + if not self._is_event_stream(self._response): + content_type = self._response.headers.get("content-type", "").partition(";")[0] raise SSEError( f"Expected response header Content-Type to contain 'text/event-stream', got {content_type!r}" ) - def _get_charset(self) -> str: + def _is_reconnect_response_usable(self, response: httpx.Response) -> bool: + """Whether a reconnected response can be resumed as an SSE stream. + + ``httpx.stream`` does not raise on non-success status, so a resume that + returns an error page (e.g. ``200 text/html`` or a ``500`` body) would + otherwise be parsed as SSE and yield garbage/zero events. Such a + response is treated as a failed attempt (back off and retry) instead. + """ + return response.status_code < 400 and self._is_event_stream(response) + + def _get_charset(self, response: Optional[httpx.Response] = None) -> str: """Extract charset from Content-Type header, fallback to UTF-8.""" - content_type = self._response.headers.get("content-type", "") + resolved = response if response is not None else self._response + content_type = resolved.headers.get("content-type", "") # Parse charset parameter using regex charset_match = re.search(r"charset=([^;\s]+)", content_type, re.IGNORECASE) @@ -60,14 +110,83 @@ def _normalize_sse_line_endings(buf: str) -> str: return buf[:-1].replace("\r", "\n") + "\r" return buf.replace("\r", "\n") - def iter_sse(self) -> Iterator[ServerSentEvent]: - self._check_content_type() - decoder = SSEDecoder() - charset = self._get_charset() - text_decoder = codecs.getincrementaldecoder(charset)(errors="replace") - + def _new_text_decoder(self, response: Optional[httpx.Response] = None) -> "codecs.IncrementalDecoder": + return codecs.getincrementaldecoder(self._get_charset(response))(errors="replace") + + def _reconnect_applicable(self) -> bool: + """Whether reconnection is configured for this stream at all. + + This is the terminator-gating half of the reconnect decision, kept + separate from :meth:`_should_reconnect` (which additionally requires a + last *dispatched* id and an unexhausted attempt budget). The split lets + a mid-stream transport error terminate consistently: + - a stream that can never reconnect (non-resumable, no terminator, + disabled, or no callback) must re-raise the error to the caller, so a + truncated stream is not mistaken for a clean completion; + - a resumable stream that has merely run out of attempts (or has no id + to resume from) ends cleanly — the same way an exhausted empty/error + -body resume already does, matching the TypeScript ``return``. + """ + return ( + self._resumable + and self._stream_terminator is not None + and self._stream_reconnection_enabled + and self._reconnect is not None + ) + + def _should_reconnect(self, last_dispatched_id: Optional[str], reconnect_attempts: int) -> bool: + """Decide whether a prematurely-ended stream should be reconnected. + + Mirrors the TypeScript ``shouldReconnect`` gating: + - only resumable SSE endpoints with a configured terminator, reconnect + enabled, and a reconnect callback are eligible (see + :meth:`_reconnect_applicable`); + - a last *dispatched* event id must exist to resume from; + - the consecutive-failed-attempt cap must not be exceeded. + """ + if not self._reconnect_applicable(): + return False + if not last_dispatched_id: + return False + max_attempts = ( + self._max_stream_reconnection_attempts + if self._max_stream_reconnection_attempts is not None + else DEFAULT_MAX_RECONNECTION_ATTEMPTS + ) + if reconnect_attempts >= max_attempts: + return False + return True + + def _reconnect_delay_seconds(self, last_retry: Optional[int]) -> float: + """Backoff before a reconnect. + + Uses the server's most recent ``retry:`` directive (milliseconds) when + present, otherwise a default of ``DEFAULT_RECONNECT_DELAY_MS``, clamped + to ``MAX_RECONNECT_DELAY_MS``. + """ + base_ms = last_retry if (last_retry is not None and last_retry > 0) else DEFAULT_RECONNECT_DELAY_MS + return min(base_ms, MAX_RECONNECT_DELAY_MS) / 1000.0 + + def _sleep_before_reconnect(self, last_retry: Optional[int]) -> None: + # ``time.sleep`` blocks the calling thread but remains interruptible by + # signals (e.g. ``KeyboardInterrupt``), which propagate out and abort + # the reconnect without issuing another request. + time.sleep(self._reconnect_delay_seconds(last_retry)) + + async def _asleep_before_reconnect(self, last_retry: Optional[int]) -> None: + # ``anyio.sleep`` is cancellation-aware: if the consumer cancels the task + # or closes the async generator mid-delay, this raises (and no further + # request is issued) instead of blocking for the whole interval. + await anyio.sleep(self._reconnect_delay_seconds(last_retry)) + + def _decode_response( + self, + response: httpx.Response, + decoder: SSEDecoder, + text_decoder: "codecs.IncrementalDecoder", + ) -> Iterator[ServerSentEvent]: buf = "" - for chunk in self._response.iter_bytes(): + for chunk in response.iter_bytes(): buf += text_decoder.decode(chunk) buf = self._normalize_sse_line_endings(buf) @@ -82,34 +201,16 @@ def iter_sse(self) -> Iterator[ServerSentEvent]: f"SSE line exceeded maximum size of {MAX_LINE_SIZE} characters without encountering a newline" ) - # Flush any remaining bytes from the incremental decoder - buf += text_decoder.decode(b"", final=True) - buf = buf.replace("\r\n", "\n").replace("\r", "\n") - - if len(buf) > MAX_LINE_SIZE: - raise SSEError( - f"SSE line exceeded maximum size of {MAX_LINE_SIZE} characters without encountering a newline" - ) - - while "\n" in buf: - line, buf = buf.split("\n", 1) - sse = decoder.decode(line) - if sse is not None: - yield sse - - if buf.strip(): - sse = decoder.decode(buf) - if sse is not None: - yield sse - - async def aiter_sse(self) -> AsyncGenerator[ServerSentEvent, None]: - self._check_content_type() - decoder = SSEDecoder() - charset = self._get_charset() - text_decoder = codecs.getincrementaldecoder(charset)(errors="replace") + yield from self._flush_decoder(buf, decoder, text_decoder) + async def _adecode_response( + self, + response: httpx.Response, + decoder: SSEDecoder, + text_decoder: "codecs.IncrementalDecoder", + ) -> AsyncGenerator[ServerSentEvent, None]: buf = "" - async for chunk in self._response.aiter_bytes(): + async for chunk in response.aiter_bytes(): buf += text_decoder.decode(chunk) buf = self._normalize_sse_line_endings(buf) @@ -124,6 +225,15 @@ async def aiter_sse(self) -> AsyncGenerator[ServerSentEvent, None]: f"SSE line exceeded maximum size of {MAX_LINE_SIZE} characters without encountering a newline" ) + for sse in self._flush_decoder(buf, decoder, text_decoder): + yield sse + + def _flush_decoder( + self, + buf: str, + decoder: SSEDecoder, + text_decoder: "codecs.IncrementalDecoder", + ) -> Iterator[ServerSentEvent]: # Flush any remaining bytes from the incremental decoder buf += text_decoder.decode(b"", final=True) buf = buf.replace("\r\n", "\n").replace("\r", "\n") @@ -144,6 +254,181 @@ async def aiter_sse(self) -> AsyncGenerator[ServerSentEvent, None]: if sse is not None: yield sse + def iter_sse(self) -> Iterator[ServerSentEvent]: + self._check_content_type() + decoder = SSEDecoder() + text_decoder = self._new_text_decoder() + + last_dispatched_id: Optional[str] = None + last_retry: Optional[int] = None + # Consecutive failed reconnection attempts. Reset to 0 whenever an event + # is successfully dispatched (reset-on-progress) — matching browser + # `EventSource` semantics: a server that emits >=1 event then drops on + # every connection can reconnect indefinitely. + reconnect_attempts = 0 + + # ``None`` means there is no live stream to read this iteration (e.g. a + # failed reconnect); the loop then re-evaluates the reconnect decision + # without re-reading an exhausted response. + response: Optional[httpx.Response] = self._response + # Context manager for a response we opened ourselves and must close. + # The initial response is owned by the caller, so it starts as None. + owned_cm: Optional[ContextManager[httpx.Response]] = None + try: + while True: + if response is not None: + events = self._decode_response(response, decoder, text_decoder) + while True: + try: + sse = next(events) + except StopIteration: + break + except SSEError: + # A protocol violation (e.g. an oversized line) is a + # genuine error, not a dropped connection; propagate it. + # Listed first because ``SSEError`` subclasses + # ``httpx.TransportError``. + raise + except httpx.TransportError: + # A transport error mid-stream (e.g. the server dropped + # the connection: ``ReadError``/``RemoteProtocolError``) + # is a premature end. Only swallow it when reconnection + # is configured for this stream; otherwise re-raise so a + # non-resumable stream still surfaces the error to the + # caller instead of looking like a clean completion. + # When reconnection is applicable but the attempt budget + # is exhausted, we ``break`` and end cleanly below — the + # same way an exhausted empty/error-body resume does, so + # give-up is consistent regardless of failure shape. + # ``next`` is used rather than ``for`` so this cannot + # swallow a ``GeneratorExit`` raised at a ``yield``. + if not self._reconnect_applicable(): + raise + break + yield sse + if sse.id: + last_dispatched_id = sse.id + if sse.retry is not None: + last_retry = sse.retry + reconnect_attempts = 0 + + if not self._should_reconnect(last_dispatched_id, reconnect_attempts): + return + reconnect_attempts += 1 + + self._sleep_before_reconnect(last_retry) + + # Close the previously-opened reconnect response before opening + # a new one so we never hold more than one extra connection. + if owned_cm is not None: + owned_cm.__exit__(None, None, None) + owned_cm = None + + assert self._reconnect is not None # guaranteed by _should_reconnect + try: + cm: ContextManager[httpx.Response] = self._reconnect(last_dispatched_id or "") + new_response = cm.__enter__() + except Exception: + # A failed reconnect consumes an attempt; back off and retry. + response = None + continue + owned_cm = cm + if new_response is None or not self._is_reconnect_response_usable(new_response): + # Null/empty body or a non-SSE/error response (e.g. 204/304, + # a 500, or an HTML error page): treat as a failed attempt. + response = None + continue + + response = new_response + # Drop any partial event left over from the dropped stream, but + # keep the last event id (per the SSE spec) and start a fresh + # incremental text decoder for the new connection. + decoder.reset_in_progress_event() + text_decoder = self._new_text_decoder(new_response) + finally: + if owned_cm is not None: + owned_cm.__exit__(None, None, None) + + async def aiter_sse(self) -> AsyncGenerator[ServerSentEvent, None]: + self._check_content_type() + decoder = SSEDecoder() + text_decoder = self._new_text_decoder() + + last_dispatched_id: Optional[str] = None + last_retry: Optional[int] = None + reconnect_attempts = 0 + + response: Optional[httpx.Response] = self._response + owned_cm: Optional[AsyncContextManager[httpx.Response]] = None + try: + while True: + if response is not None: + events = self._adecode_response(response, decoder, text_decoder) + while True: + try: + sse = await events.__anext__() + except StopAsyncIteration: + break + except SSEError: + # A protocol violation (e.g. an oversized line) is a + # genuine error, not a dropped connection; propagate it. + # Listed first because ``SSEError`` subclasses + # ``httpx.TransportError``. + raise + except httpx.TransportError: + # A transport error mid-stream (e.g. the server dropped + # the connection: ``ReadError``/``RemoteProtocolError``) + # is a premature end. Only swallow it when reconnection + # is configured for this stream; otherwise re-raise so a + # non-resumable stream still surfaces the error to the + # caller instead of looking like a clean completion. + # When reconnection is applicable but the attempt budget + # is exhausted, we ``break`` and end cleanly below — the + # same way an exhausted empty/error-body resume does, so + # give-up is consistent regardless of failure shape. + if not self._reconnect_applicable(): + raise + break + yield sse + if sse.id: + last_dispatched_id = sse.id + if sse.retry is not None: + last_retry = sse.retry + reconnect_attempts = 0 + + if not self._should_reconnect(last_dispatched_id, reconnect_attempts): + return + reconnect_attempts += 1 + + await self._asleep_before_reconnect(last_retry) + + if owned_cm is not None: + await owned_cm.__aexit__(None, None, None) + owned_cm = None + + assert self._reconnect is not None # guaranteed by _should_reconnect + try: + cm: AsyncContextManager[httpx.Response] = self._reconnect(last_dispatched_id or "") + new_response = await cm.__aenter__() + except Exception: + response = None + continue + owned_cm = cm + if new_response is None or not self._is_reconnect_response_usable(new_response): + response = None + continue + + response = new_response + decoder.reset_in_progress_event() + text_decoder = self._new_text_decoder(new_response) + finally: + if owned_cm is not None: + # Shield the close so a cancellation delivered while reading a + # reconnected response still fully tears the connection down + # instead of leaking it until the client is closed. + with anyio.CancelScope(shield=True): + await owned_cm.__aexit__(None, None, None) + @contextmanager def connect_sse(client: httpx.Client, method: str, url: str, **kwargs: Any) -> Iterator[EventSource]: diff --git a/src/schematic/core/http_sse/_decoders.py b/src/schematic/core/http_sse/_decoders.py index 339b089..1f6b35e 100644 --- a/src/schematic/core/http_sse/_decoders.py +++ b/src/schematic/core/http_sse/_decoders.py @@ -12,6 +12,19 @@ def __init__(self) -> None: self._last_event_id = "" self._retry: Optional[int] = None + def reset_in_progress_event(self) -> None: + """Discard any partially-parsed (undispatched) event. + + Used when a stream ends mid-event before reconnecting: the buffered + ``event``/``data``/``retry`` fields of the never-dispatched event must + be dropped so they do not corrupt the first event of the reconnected + stream. Per the SSE spec the last event id is *not* reset here — it + persists across connections. + """ + self._event = "" + self._data = [] + self._retry = None + def decode(self, line: str) -> Optional[ServerSentEvent]: # See: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation # noqa: E501 diff --git a/src/schematic/core/jsonable_encoder.py b/src/schematic/core/jsonable_encoder.py index 5b0902e..f638cc9 100644 --- a/src/schematic/core/jsonable_encoder.py +++ b/src/schematic/core/jsonable_encoder.py @@ -15,6 +15,7 @@ from pathlib import PurePath from types import GeneratorType from typing import Any, Callable, Dict, List, Optional, Set, Union +from urllib.parse import quote import pydantic from .datetime_utils import serialize_datetime @@ -118,3 +119,15 @@ def encode_path_param(obj: Any) -> str: if isinstance(obj, bool): return "true" if obj else "false" return str(jsonable_encoder(obj)) + + +def quote_path_param(obj: Any) -> str: + """Encode a value for use in a URL path segment, percent-encoding it. + + Same as encode_path_param, except the result is percent-encoded so + that a value containing "/" or ".." cannot change which endpoint + the request resolves to. + """ + if isinstance(obj, bool): + return "true" if obj else "false" + return quote(str(jsonable_encoder(obj)), safe="") diff --git a/src/schematic/core/request_options.py b/src/schematic/core/request_options.py index 1b38804..caa6f66 100644 --- a/src/schematic/core/request_options.py +++ b/src/schematic/core/request_options.py @@ -14,7 +14,9 @@ class RequestOptions(typing.TypedDict, total=False): This is used primarily as an optional final parameter for service functions. Attributes: - - timeout_in_seconds: int. The number of seconds to await an API call before timing out. + - timeout: float. The number of seconds to await an API call before timing out. + + - timeout_in_seconds: int. Deprecated alias for `timeout`; both are in seconds. Prefer `timeout`. - max_retries: int. The max number of retries to attempt if the API call fails. @@ -27,9 +29,12 @@ class RequestOptions(typing.TypedDict, total=False): - 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: NotRequired[float] 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] + stream_reconnection_enabled: NotRequired[bool] + max_stream_reconnection_attempts: NotRequired[int] diff --git a/src/schematic/credits/client.py b/src/schematic/credits/client.py index aff68c4..d261735 100644 --- a/src/schematic/credits/client.py +++ b/src/schematic/credits/client.py @@ -462,6 +462,7 @@ def create_credit_bundle( currency: str, price_per_unit: int, bundle_type: typing.Optional[BillingCreditBundleType] = OMIT, + compatible_plan_ids: typing.Optional[typing.Sequence[str]] = OMIT, currency_prices: typing.Optional[typing.Sequence[CreditBundleCurrencyPriceRequestBody]] = OMIT, expiry_type: typing.Optional[BillingCreditExpiryType] = OMIT, expiry_unit: typing.Optional[BillingCreditExpiryUnit] = OMIT, @@ -484,6 +485,9 @@ def create_credit_bundle( bundle_type : typing.Optional[BillingCreditBundleType] + compatible_plan_ids : typing.Optional[typing.Sequence[str]] + Plans whose companies may purchase this bundle. Omitted or empty means the bundle is purchasable on every plan. + currency_prices : typing.Optional[typing.Sequence[CreditBundleCurrencyPriceRequestBody]] expiry_type : typing.Optional[BillingCreditExpiryType] @@ -526,6 +530,7 @@ def create_credit_bundle( currency=currency, price_per_unit=price_per_unit, bundle_type=bundle_type, + compatible_plan_ids=compatible_plan_ids, currency_prices=currency_prices, expiry_type=expiry_type, expiry_unit=expiry_unit, @@ -574,6 +579,7 @@ def update_credit_bundle_details( *, bundle_name: str, price_per_unit: int, + compatible_plan_ids: typing.Optional[typing.Sequence[str]] = OMIT, currency_prices: typing.Optional[typing.Sequence[CreditBundleCurrencyPriceRequestBody]] = OMIT, expiry_type: typing.Optional[BillingCreditExpiryType] = OMIT, expiry_unit: typing.Optional[BillingCreditExpiryUnit] = OMIT, @@ -593,6 +599,9 @@ def update_credit_bundle_details( price_per_unit : int + compatible_plan_ids : typing.Optional[typing.Sequence[str]] + Plans whose companies may purchase this bundle. Omitted leaves compatibility unchanged; empty resets the bundle to purchasable on every plan. + currency_prices : typing.Optional[typing.Sequence[CreditBundleCurrencyPriceRequestBody]] expiry_type : typing.Optional[BillingCreditExpiryType] @@ -632,6 +641,7 @@ def update_credit_bundle_details( bundle_id, bundle_name=bundle_name, price_per_unit=price_per_unit, + compatible_plan_ids=compatible_plan_ids, currency_prices=currency_prices, expiry_type=expiry_type, expiry_unit=expiry_unit, @@ -908,7 +918,7 @@ def grant_billing_credits_to_company( def count_company_grants( self, *, - company_id: typing.Optional[str] = None, + company_id: str, order: typing.Optional[CreditGrantSortOrder] = None, dir: typing.Optional[SortDirection] = None, limit: typing.Optional[int] = None, @@ -918,7 +928,7 @@ def count_company_grants( """ Parameters ---------- - company_id : typing.Optional[str] + company_id : str order : typing.Optional[CreditGrantSortOrder] @@ -961,7 +971,7 @@ def count_company_grants( def list_company_grants( self, *, - company_id: typing.Optional[str] = None, + company_id: str, order: typing.Optional[CreditGrantSortOrder] = None, dir: typing.Optional[SortDirection] = None, limit: typing.Optional[int] = None, @@ -971,7 +981,7 @@ def list_company_grants( """ Parameters ---------- - company_id : typing.Optional[str] + company_id : str order : typing.Optional[CreditGrantSortOrder] @@ -1333,6 +1343,7 @@ def create_billing_plan_credit_grant( auto_topup_threshold_credits: typing.Optional[int] = OMIT, auto_topup_threshold_percent: typing.Optional[int] = OMIT, can_buy_bundles: typing.Optional[bool] = OMIT, + company_credit_amount: typing.Optional[int] = OMIT, expiry_type: typing.Optional[BillingCreditExpiryType] = OMIT, expiry_unit: typing.Optional[BillingCreditExpiryUnit] = OMIT, expiry_unit_count: typing.Optional[int] = OMIT, @@ -1379,6 +1390,10 @@ def create_billing_plan_credit_grant( auto_topup_threshold_percent : typing.Optional[int] can_buy_bundles : typing.Optional[bool] + Deprecated: use compatible_plan_ids on credit bundles instead. Still accepted; writes through to the credit's bundle compatibility. + + company_credit_amount : typing.Optional[int] + Credits granted once per company on top of the per-license amount. Only valid when scaling is per_license. Defaults to 0. expiry_type : typing.Optional[BillingCreditExpiryType] @@ -1440,6 +1455,7 @@ def create_billing_plan_credit_grant( auto_topup_threshold_credits=auto_topup_threshold_credits, auto_topup_threshold_percent=auto_topup_threshold_percent, can_buy_bundles=can_buy_bundles, + company_credit_amount=company_credit_amount, expiry_type=expiry_type, expiry_unit=expiry_unit, expiry_unit_count=expiry_unit_count, @@ -1503,6 +1519,7 @@ def update_billing_plan_credit_grant( auto_topup_threshold_credits: typing.Optional[int] = OMIT, auto_topup_threshold_percent: typing.Optional[int] = OMIT, can_buy_bundles: typing.Optional[bool] = OMIT, + company_credit_amount: typing.Optional[int] = OMIT, credit_amount: typing.Optional[int] = OMIT, expiry_type: typing.Optional[BillingCreditExpiryType] = OMIT, expiry_unit: typing.Optional[BillingCreditExpiryUnit] = OMIT, @@ -1546,6 +1563,10 @@ def update_billing_plan_credit_grant( auto_topup_threshold_percent : typing.Optional[int] can_buy_bundles : typing.Optional[bool] + Deprecated: use compatible_plan_ids on credit bundles instead. Still accepted; writes through to the credit's bundle compatibility. + + company_credit_amount : typing.Optional[int] + Credits granted once per company on top of the per-license amount. Only valid when the grant scales per license. credit_amount : typing.Optional[int] @@ -1556,7 +1577,7 @@ def update_billing_plan_credit_grant( expiry_unit_count : typing.Optional[int] license_id : typing.Optional[str] - The license whose quantity scales this grant. Cannot be changed after creation. + The license whose quantity scales this grant. Cleared when the grant moves off per-license scaling. reset_type : typing.Optional[BillingPlanCreditGrantResetType] @@ -1564,7 +1585,7 @@ def update_billing_plan_credit_grant( Percentage of unused credits that carry over when this grant resets. Only applies when reset_type is plan_period. Rolled-over credits expire at the next reset and are not rolled again. scaling : typing.Optional[PlanCreditGrantScaling] - Whether the grant is a fixed amount per company, or issued once per license the company holds. Cannot be changed after creation. + Whether the grant is a fixed amount per company, or issued once per license the company holds. Changing this re-issues the credits companies already hold for this grant. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1603,6 +1624,7 @@ def update_billing_plan_credit_grant( auto_topup_threshold_credits=auto_topup_threshold_credits, auto_topup_threshold_percent=auto_topup_threshold_percent, can_buy_bundles=can_buy_bundles, + company_credit_amount=company_credit_amount, credit_amount=credit_amount, expiry_type=expiry_type, expiry_unit=expiry_unit, @@ -2332,6 +2354,7 @@ async def create_credit_bundle( currency: str, price_per_unit: int, bundle_type: typing.Optional[BillingCreditBundleType] = OMIT, + compatible_plan_ids: typing.Optional[typing.Sequence[str]] = OMIT, currency_prices: typing.Optional[typing.Sequence[CreditBundleCurrencyPriceRequestBody]] = OMIT, expiry_type: typing.Optional[BillingCreditExpiryType] = OMIT, expiry_unit: typing.Optional[BillingCreditExpiryUnit] = OMIT, @@ -2354,6 +2377,9 @@ async def create_credit_bundle( bundle_type : typing.Optional[BillingCreditBundleType] + compatible_plan_ids : typing.Optional[typing.Sequence[str]] + Plans whose companies may purchase this bundle. Omitted or empty means the bundle is purchasable on every plan. + currency_prices : typing.Optional[typing.Sequence[CreditBundleCurrencyPriceRequestBody]] expiry_type : typing.Optional[BillingCreditExpiryType] @@ -2404,6 +2430,7 @@ async def main() -> None: currency=currency, price_per_unit=price_per_unit, bundle_type=bundle_type, + compatible_plan_ids=compatible_plan_ids, currency_prices=currency_prices, expiry_type=expiry_type, expiry_unit=expiry_unit, @@ -2460,6 +2487,7 @@ async def update_credit_bundle_details( *, bundle_name: str, price_per_unit: int, + compatible_plan_ids: typing.Optional[typing.Sequence[str]] = OMIT, currency_prices: typing.Optional[typing.Sequence[CreditBundleCurrencyPriceRequestBody]] = OMIT, expiry_type: typing.Optional[BillingCreditExpiryType] = OMIT, expiry_unit: typing.Optional[BillingCreditExpiryUnit] = OMIT, @@ -2479,6 +2507,9 @@ async def update_credit_bundle_details( price_per_unit : int + compatible_plan_ids : typing.Optional[typing.Sequence[str]] + Plans whose companies may purchase this bundle. Omitted leaves compatibility unchanged; empty resets the bundle to purchasable on every plan. + currency_prices : typing.Optional[typing.Sequence[CreditBundleCurrencyPriceRequestBody]] expiry_type : typing.Optional[BillingCreditExpiryType] @@ -2526,6 +2557,7 @@ async def main() -> None: bundle_id, bundle_name=bundle_name, price_per_unit=price_per_unit, + compatible_plan_ids=compatible_plan_ids, currency_prices=currency_prices, expiry_type=expiry_type, expiry_unit=expiry_unit, @@ -2842,7 +2874,7 @@ async def main() -> None: async def count_company_grants( self, *, - company_id: typing.Optional[str] = None, + company_id: str, order: typing.Optional[CreditGrantSortOrder] = None, dir: typing.Optional[SortDirection] = None, limit: typing.Optional[int] = None, @@ -2852,7 +2884,7 @@ async def count_company_grants( """ Parameters ---------- - company_id : typing.Optional[str] + company_id : str order : typing.Optional[CreditGrantSortOrder] @@ -2903,7 +2935,7 @@ async def main() -> None: async def list_company_grants( self, *, - company_id: typing.Optional[str] = None, + company_id: str, order: typing.Optional[CreditGrantSortOrder] = None, dir: typing.Optional[SortDirection] = None, limit: typing.Optional[int] = None, @@ -2913,7 +2945,7 @@ async def list_company_grants( """ Parameters ---------- - company_id : typing.Optional[str] + company_id : str order : typing.Optional[CreditGrantSortOrder] @@ -3333,6 +3365,7 @@ async def create_billing_plan_credit_grant( auto_topup_threshold_credits: typing.Optional[int] = OMIT, auto_topup_threshold_percent: typing.Optional[int] = OMIT, can_buy_bundles: typing.Optional[bool] = OMIT, + company_credit_amount: typing.Optional[int] = OMIT, expiry_type: typing.Optional[BillingCreditExpiryType] = OMIT, expiry_unit: typing.Optional[BillingCreditExpiryUnit] = OMIT, expiry_unit_count: typing.Optional[int] = OMIT, @@ -3379,6 +3412,10 @@ async def create_billing_plan_credit_grant( auto_topup_threshold_percent : typing.Optional[int] can_buy_bundles : typing.Optional[bool] + Deprecated: use compatible_plan_ids on credit bundles instead. Still accepted; writes through to the credit's bundle compatibility. + + company_credit_amount : typing.Optional[int] + Credits granted once per company on top of the per-license amount. Only valid when scaling is per_license. Defaults to 0. expiry_type : typing.Optional[BillingCreditExpiryType] @@ -3448,6 +3485,7 @@ async def main() -> None: auto_topup_threshold_credits=auto_topup_threshold_credits, auto_topup_threshold_percent=auto_topup_threshold_percent, can_buy_bundles=can_buy_bundles, + company_credit_amount=company_credit_amount, expiry_type=expiry_type, expiry_unit=expiry_unit, expiry_unit_count=expiry_unit_count, @@ -3519,6 +3557,7 @@ async def update_billing_plan_credit_grant( auto_topup_threshold_credits: typing.Optional[int] = OMIT, auto_topup_threshold_percent: typing.Optional[int] = OMIT, can_buy_bundles: typing.Optional[bool] = OMIT, + company_credit_amount: typing.Optional[int] = OMIT, credit_amount: typing.Optional[int] = OMIT, expiry_type: typing.Optional[BillingCreditExpiryType] = OMIT, expiry_unit: typing.Optional[BillingCreditExpiryUnit] = OMIT, @@ -3562,6 +3601,10 @@ async def update_billing_plan_credit_grant( auto_topup_threshold_percent : typing.Optional[int] can_buy_bundles : typing.Optional[bool] + Deprecated: use compatible_plan_ids on credit bundles instead. Still accepted; writes through to the credit's bundle compatibility. + + company_credit_amount : typing.Optional[int] + Credits granted once per company on top of the per-license amount. Only valid when the grant scales per license. credit_amount : typing.Optional[int] @@ -3572,7 +3615,7 @@ async def update_billing_plan_credit_grant( expiry_unit_count : typing.Optional[int] license_id : typing.Optional[str] - The license whose quantity scales this grant. Cannot be changed after creation. + The license whose quantity scales this grant. Cleared when the grant moves off per-license scaling. reset_type : typing.Optional[BillingPlanCreditGrantResetType] @@ -3580,7 +3623,7 @@ async def update_billing_plan_credit_grant( Percentage of unused credits that carry over when this grant resets. Only applies when reset_type is plan_period. Rolled-over credits expire at the next reset and are not rolled again. scaling : typing.Optional[PlanCreditGrantScaling] - Whether the grant is a fixed amount per company, or issued once per license the company holds. Cannot be changed after creation. + Whether the grant is a fixed amount per company, or issued once per license the company holds. Changing this re-issues the credits companies already hold for this grant. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -3627,6 +3670,7 @@ async def main() -> None: auto_topup_threshold_credits=auto_topup_threshold_credits, auto_topup_threshold_percent=auto_topup_threshold_percent, can_buy_bundles=can_buy_bundles, + company_credit_amount=company_credit_amount, credit_amount=credit_amount, expiry_type=expiry_type, expiry_unit=expiry_unit, diff --git a/src/schematic/credits/raw_client.py b/src/schematic/credits/raw_client.py index 48745e0..babcaed 100644 --- a/src/schematic/credits/raw_client.py +++ b/src/schematic/credits/raw_client.py @@ -945,6 +945,7 @@ def create_credit_bundle( currency: str, price_per_unit: int, bundle_type: typing.Optional[BillingCreditBundleType] = OMIT, + compatible_plan_ids: typing.Optional[typing.Sequence[str]] = OMIT, currency_prices: typing.Optional[typing.Sequence[CreditBundleCurrencyPriceRequestBody]] = OMIT, expiry_type: typing.Optional[BillingCreditExpiryType] = OMIT, expiry_unit: typing.Optional[BillingCreditExpiryUnit] = OMIT, @@ -967,6 +968,9 @@ def create_credit_bundle( bundle_type : typing.Optional[BillingCreditBundleType] + compatible_plan_ids : typing.Optional[typing.Sequence[str]] + Plans whose companies may purchase this bundle. Omitted or empty means the bundle is purchasable on every plan. + currency_prices : typing.Optional[typing.Sequence[CreditBundleCurrencyPriceRequestBody]] expiry_type : typing.Optional[BillingCreditExpiryType] @@ -995,6 +999,7 @@ def create_credit_bundle( json={ "bundle_name": bundle_name, "bundle_type": bundle_type, + "compatible_plan_ids": compatible_plan_ids, "credit_id": credit_id, "currency": currency, "currency_prices": convert_and_respect_annotation_metadata( @@ -1189,6 +1194,7 @@ def update_credit_bundle_details( *, bundle_name: str, price_per_unit: int, + compatible_plan_ids: typing.Optional[typing.Sequence[str]] = OMIT, currency_prices: typing.Optional[typing.Sequence[CreditBundleCurrencyPriceRequestBody]] = OMIT, expiry_type: typing.Optional[BillingCreditExpiryType] = OMIT, expiry_unit: typing.Optional[BillingCreditExpiryUnit] = OMIT, @@ -1208,6 +1214,9 @@ def update_credit_bundle_details( price_per_unit : int + compatible_plan_ids : typing.Optional[typing.Sequence[str]] + Plans whose companies may purchase this bundle. Omitted leaves compatibility unchanged; empty resets the bundle to purchasable on every plan. + currency_prices : typing.Optional[typing.Sequence[CreditBundleCurrencyPriceRequestBody]] expiry_type : typing.Optional[BillingCreditExpiryType] @@ -1235,6 +1244,7 @@ def update_credit_bundle_details( method="PUT", json={ "bundle_name": bundle_name, + "compatible_plan_ids": compatible_plan_ids, "currency_prices": convert_and_respect_annotation_metadata( object_=currency_prices, annotation=typing.Sequence[CreditBundleCurrencyPriceRequestBody], @@ -1947,7 +1957,7 @@ def grant_billing_credits_to_company( def count_company_grants( self, *, - company_id: typing.Optional[str] = None, + company_id: str, order: typing.Optional[CreditGrantSortOrder] = None, dir: typing.Optional[SortDirection] = None, limit: typing.Optional[int] = None, @@ -1957,7 +1967,7 @@ def count_company_grants( """ Parameters ---------- - company_id : typing.Optional[str] + company_id : str order : typing.Optional[CreditGrantSortOrder] @@ -2070,7 +2080,7 @@ def count_company_grants( def list_company_grants( self, *, - company_id: typing.Optional[str] = None, + company_id: str, order: typing.Optional[CreditGrantSortOrder] = None, dir: typing.Optional[SortDirection] = None, limit: typing.Optional[int] = None, @@ -2080,7 +2090,7 @@ def list_company_grants( """ Parameters ---------- - company_id : typing.Optional[str] + company_id : str order : typing.Optional[CreditGrantSortOrder] @@ -2932,6 +2942,7 @@ def create_billing_plan_credit_grant( auto_topup_threshold_credits: typing.Optional[int] = OMIT, auto_topup_threshold_percent: typing.Optional[int] = OMIT, can_buy_bundles: typing.Optional[bool] = OMIT, + company_credit_amount: typing.Optional[int] = OMIT, expiry_type: typing.Optional[BillingCreditExpiryType] = OMIT, expiry_unit: typing.Optional[BillingCreditExpiryUnit] = OMIT, expiry_unit_count: typing.Optional[int] = OMIT, @@ -2978,6 +2989,10 @@ def create_billing_plan_credit_grant( auto_topup_threshold_percent : typing.Optional[int] can_buy_bundles : typing.Optional[bool] + Deprecated: use compatible_plan_ids on credit bundles instead. Still accepted; writes through to the credit's bundle compatibility. + + company_credit_amount : typing.Optional[int] + Credits granted once per company on top of the per-license amount. Only valid when scaling is per_license. Defaults to 0. expiry_type : typing.Optional[BillingCreditExpiryType] @@ -3022,6 +3037,7 @@ def create_billing_plan_credit_grant( "auto_topup_threshold_credits": auto_topup_threshold_credits, "auto_topup_threshold_percent": auto_topup_threshold_percent, "can_buy_bundles": can_buy_bundles, + "company_credit_amount": company_credit_amount, "credit_amount": credit_amount, "credit_id": credit_id, "expiry_type": expiry_type, @@ -3227,6 +3243,7 @@ def update_billing_plan_credit_grant( auto_topup_threshold_credits: typing.Optional[int] = OMIT, auto_topup_threshold_percent: typing.Optional[int] = OMIT, can_buy_bundles: typing.Optional[bool] = OMIT, + company_credit_amount: typing.Optional[int] = OMIT, credit_amount: typing.Optional[int] = OMIT, expiry_type: typing.Optional[BillingCreditExpiryType] = OMIT, expiry_unit: typing.Optional[BillingCreditExpiryUnit] = OMIT, @@ -3270,6 +3287,10 @@ def update_billing_plan_credit_grant( auto_topup_threshold_percent : typing.Optional[int] can_buy_bundles : typing.Optional[bool] + Deprecated: use compatible_plan_ids on credit bundles instead. Still accepted; writes through to the credit's bundle compatibility. + + company_credit_amount : typing.Optional[int] + Credits granted once per company on top of the per-license amount. Only valid when the grant scales per license. credit_amount : typing.Optional[int] @@ -3280,7 +3301,7 @@ def update_billing_plan_credit_grant( expiry_unit_count : typing.Optional[int] license_id : typing.Optional[str] - The license whose quantity scales this grant. Cannot be changed after creation. + The license whose quantity scales this grant. Cleared when the grant moves off per-license scaling. reset_type : typing.Optional[BillingPlanCreditGrantResetType] @@ -3288,7 +3309,7 @@ def update_billing_plan_credit_grant( Percentage of unused credits that carry over when this grant resets. Only applies when reset_type is plan_period. Rolled-over credits expire at the next reset and are not rolled again. scaling : typing.Optional[PlanCreditGrantScaling] - Whether the grant is a fixed amount per company, or issued once per license the company holds. Cannot be changed after creation. + Whether the grant is a fixed amount per company, or issued once per license the company holds. Changing this re-issues the credits companies already hold for this grant. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -3314,6 +3335,7 @@ def update_billing_plan_credit_grant( "auto_topup_threshold_credits": auto_topup_threshold_credits, "auto_topup_threshold_percent": auto_topup_threshold_percent, "can_buy_bundles": can_buy_bundles, + "company_credit_amount": company_credit_amount, "credit_amount": credit_amount, "expiry_type": expiry_type, "expiry_unit": expiry_unit, @@ -4795,6 +4817,7 @@ async def create_credit_bundle( currency: str, price_per_unit: int, bundle_type: typing.Optional[BillingCreditBundleType] = OMIT, + compatible_plan_ids: typing.Optional[typing.Sequence[str]] = OMIT, currency_prices: typing.Optional[typing.Sequence[CreditBundleCurrencyPriceRequestBody]] = OMIT, expiry_type: typing.Optional[BillingCreditExpiryType] = OMIT, expiry_unit: typing.Optional[BillingCreditExpiryUnit] = OMIT, @@ -4817,6 +4840,9 @@ async def create_credit_bundle( bundle_type : typing.Optional[BillingCreditBundleType] + compatible_plan_ids : typing.Optional[typing.Sequence[str]] + Plans whose companies may purchase this bundle. Omitted or empty means the bundle is purchasable on every plan. + currency_prices : typing.Optional[typing.Sequence[CreditBundleCurrencyPriceRequestBody]] expiry_type : typing.Optional[BillingCreditExpiryType] @@ -4845,6 +4871,7 @@ async def create_credit_bundle( json={ "bundle_name": bundle_name, "bundle_type": bundle_type, + "compatible_plan_ids": compatible_plan_ids, "credit_id": credit_id, "currency": currency, "currency_prices": convert_and_respect_annotation_metadata( @@ -5039,6 +5066,7 @@ async def update_credit_bundle_details( *, bundle_name: str, price_per_unit: int, + compatible_plan_ids: typing.Optional[typing.Sequence[str]] = OMIT, currency_prices: typing.Optional[typing.Sequence[CreditBundleCurrencyPriceRequestBody]] = OMIT, expiry_type: typing.Optional[BillingCreditExpiryType] = OMIT, expiry_unit: typing.Optional[BillingCreditExpiryUnit] = OMIT, @@ -5058,6 +5086,9 @@ async def update_credit_bundle_details( price_per_unit : int + compatible_plan_ids : typing.Optional[typing.Sequence[str]] + Plans whose companies may purchase this bundle. Omitted leaves compatibility unchanged; empty resets the bundle to purchasable on every plan. + currency_prices : typing.Optional[typing.Sequence[CreditBundleCurrencyPriceRequestBody]] expiry_type : typing.Optional[BillingCreditExpiryType] @@ -5085,6 +5116,7 @@ async def update_credit_bundle_details( method="PUT", json={ "bundle_name": bundle_name, + "compatible_plan_ids": compatible_plan_ids, "currency_prices": convert_and_respect_annotation_metadata( object_=currency_prices, annotation=typing.Sequence[CreditBundleCurrencyPriceRequestBody], @@ -5797,7 +5829,7 @@ async def grant_billing_credits_to_company( async def count_company_grants( self, *, - company_id: typing.Optional[str] = None, + company_id: str, order: typing.Optional[CreditGrantSortOrder] = None, dir: typing.Optional[SortDirection] = None, limit: typing.Optional[int] = None, @@ -5807,7 +5839,7 @@ async def count_company_grants( """ Parameters ---------- - company_id : typing.Optional[str] + company_id : str order : typing.Optional[CreditGrantSortOrder] @@ -5920,7 +5952,7 @@ async def count_company_grants( async def list_company_grants( self, *, - company_id: typing.Optional[str] = None, + company_id: str, order: typing.Optional[CreditGrantSortOrder] = None, dir: typing.Optional[SortDirection] = None, limit: typing.Optional[int] = None, @@ -5930,7 +5962,7 @@ async def list_company_grants( """ Parameters ---------- - company_id : typing.Optional[str] + company_id : str order : typing.Optional[CreditGrantSortOrder] @@ -6782,6 +6814,7 @@ async def create_billing_plan_credit_grant( auto_topup_threshold_credits: typing.Optional[int] = OMIT, auto_topup_threshold_percent: typing.Optional[int] = OMIT, can_buy_bundles: typing.Optional[bool] = OMIT, + company_credit_amount: typing.Optional[int] = OMIT, expiry_type: typing.Optional[BillingCreditExpiryType] = OMIT, expiry_unit: typing.Optional[BillingCreditExpiryUnit] = OMIT, expiry_unit_count: typing.Optional[int] = OMIT, @@ -6828,6 +6861,10 @@ async def create_billing_plan_credit_grant( auto_topup_threshold_percent : typing.Optional[int] can_buy_bundles : typing.Optional[bool] + Deprecated: use compatible_plan_ids on credit bundles instead. Still accepted; writes through to the credit's bundle compatibility. + + company_credit_amount : typing.Optional[int] + Credits granted once per company on top of the per-license amount. Only valid when scaling is per_license. Defaults to 0. expiry_type : typing.Optional[BillingCreditExpiryType] @@ -6872,6 +6909,7 @@ async def create_billing_plan_credit_grant( "auto_topup_threshold_credits": auto_topup_threshold_credits, "auto_topup_threshold_percent": auto_topup_threshold_percent, "can_buy_bundles": can_buy_bundles, + "company_credit_amount": company_credit_amount, "credit_amount": credit_amount, "credit_id": credit_id, "expiry_type": expiry_type, @@ -7077,6 +7115,7 @@ async def update_billing_plan_credit_grant( auto_topup_threshold_credits: typing.Optional[int] = OMIT, auto_topup_threshold_percent: typing.Optional[int] = OMIT, can_buy_bundles: typing.Optional[bool] = OMIT, + company_credit_amount: typing.Optional[int] = OMIT, credit_amount: typing.Optional[int] = OMIT, expiry_type: typing.Optional[BillingCreditExpiryType] = OMIT, expiry_unit: typing.Optional[BillingCreditExpiryUnit] = OMIT, @@ -7120,6 +7159,10 @@ async def update_billing_plan_credit_grant( auto_topup_threshold_percent : typing.Optional[int] can_buy_bundles : typing.Optional[bool] + Deprecated: use compatible_plan_ids on credit bundles instead. Still accepted; writes through to the credit's bundle compatibility. + + company_credit_amount : typing.Optional[int] + Credits granted once per company on top of the per-license amount. Only valid when the grant scales per license. credit_amount : typing.Optional[int] @@ -7130,7 +7173,7 @@ async def update_billing_plan_credit_grant( expiry_unit_count : typing.Optional[int] license_id : typing.Optional[str] - The license whose quantity scales this grant. Cannot be changed after creation. + The license whose quantity scales this grant. Cleared when the grant moves off per-license scaling. reset_type : typing.Optional[BillingPlanCreditGrantResetType] @@ -7138,7 +7181,7 @@ async def update_billing_plan_credit_grant( Percentage of unused credits that carry over when this grant resets. Only applies when reset_type is plan_period. Rolled-over credits expire at the next reset and are not rolled again. scaling : typing.Optional[PlanCreditGrantScaling] - Whether the grant is a fixed amount per company, or issued once per license the company holds. Cannot be changed after creation. + Whether the grant is a fixed amount per company, or issued once per license the company holds. Changing this re-issues the credits companies already hold for this grant. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -7164,6 +7207,7 @@ async def update_billing_plan_credit_grant( "auto_topup_threshold_credits": auto_topup_threshold_credits, "auto_topup_threshold_percent": auto_topup_threshold_percent, "can_buy_bundles": can_buy_bundles, + "company_credit_amount": company_credit_amount, "credit_amount": credit_amount, "expiry_type": expiry_type, "expiry_unit": expiry_unit, diff --git a/src/schematic/entitlements/__init__.py b/src/schematic/entitlements/__init__.py index 123a90e..81f165c 100644 --- a/src/schematic/entitlements/__init__.py +++ b/src/schematic/entitlements/__init__.py @@ -36,6 +36,8 @@ ListCompanyOverridesResponse, ListFeatureCompaniesParams, ListFeatureCompaniesResponse, + ListFeatureUsageHistoryParams, + ListFeatureUsageHistoryResponse, ListFeatureUsageParams, ListFeatureUsageResponse, ListFeatureUsersParams, @@ -76,6 +78,8 @@ "ListCompanyOverridesResponse": ".types", "ListFeatureCompaniesParams": ".types", "ListFeatureCompaniesResponse": ".types", + "ListFeatureUsageHistoryParams": ".types", + "ListFeatureUsageHistoryResponse": ".types", "ListFeatureUsageParams": ".types", "ListFeatureUsageResponse": ".types", "ListFeatureUsersParams": ".types", @@ -139,6 +143,8 @@ def __dir__(): "ListCompanyOverridesResponse", "ListFeatureCompaniesParams", "ListFeatureCompaniesResponse", + "ListFeatureUsageHistoryParams", + "ListFeatureUsageHistoryResponse", "ListFeatureUsageParams", "ListFeatureUsageResponse", "ListFeatureUsersParams", diff --git a/src/schematic/entitlements/client.py b/src/schematic/entitlements/client.py index d4d72c9..f361d20 100644 --- a/src/schematic/entitlements/client.py +++ b/src/schematic/entitlements/client.py @@ -34,6 +34,7 @@ from .types.get_user_usage_detail_response import GetUserUsageDetailResponse from .types.list_company_overrides_response import ListCompanyOverridesResponse from .types.list_feature_companies_response import ListFeatureCompaniesResponse +from .types.list_feature_usage_history_response import ListFeatureUsageHistoryResponse from .types.list_feature_usage_response import ListFeatureUsageResponse from .types.list_feature_users_response import ListFeatureUsersResponse from .types.list_plan_entitlements_response import ListPlanEntitlementsResponse @@ -629,6 +630,85 @@ def list_feature_usage( ) return _response.data + def list_feature_usage_history( + self, + *, + end_time: dt.datetime, + start_time: dt.datetime, + company_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + feature_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + granularity: typing.Optional[TimeSeriesGranularity] = None, + limit: typing.Optional[int] = None, + offset: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> ListFeatureUsageHistoryResponse: + """ + Parameters + ---------- + end_time : dt.datetime + Exclusive end of the window; must fall on an hour boundary + + start_time : dt.datetime + Inclusive start of the window; must fall on an hour boundary + + company_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Restrict to these company IDs; omit for every company in the environment + + feature_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Restrict to these event features; omit for every event feature in the environment. Where several features measure the same event, each is reported separately and a page may carry more rows than the requested limit + + granularity : typing.Optional[TimeSeriesGranularity] + Bucket the window; omit for a single total per company and feature + + limit : typing.Optional[int] + Page limit (default 100) + + offset : typing.Optional[int] + Page offset (default 0) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ListFeatureUsageHistoryResponse + OK + + Examples + -------- + import datetime + + from schematic import Schematic + + client = Schematic( + api_key="YOUR_API_KEY", + ) + client.entitlements.list_feature_usage_history( + company_ids=["company_ids"], + end_time=datetime.datetime.fromisoformat( + "2024-01-15 09:30:00+00:00", + ), + feature_ids=["feature_ids"], + granularity="daily", + start_time=datetime.datetime.fromisoformat( + "2024-01-15 09:30:00+00:00", + ), + limit=1000000, + offset=1000000, + ) + """ + _response = self._raw_client.list_feature_usage_history( + end_time=end_time, + start_time=start_time, + company_ids=company_ids, + feature_ids=feature_ids, + granularity=granularity, + limit=limit, + offset=offset, + request_options=request_options, + ) + return _response.data + def get_feature_usage_time_series( self, *, @@ -2487,6 +2567,92 @@ async def main() -> None: ) return _response.data + async def list_feature_usage_history( + self, + *, + end_time: dt.datetime, + start_time: dt.datetime, + company_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + feature_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + granularity: typing.Optional[TimeSeriesGranularity] = None, + limit: typing.Optional[int] = None, + offset: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> ListFeatureUsageHistoryResponse: + """ + Parameters + ---------- + end_time : dt.datetime + Exclusive end of the window; must fall on an hour boundary + + start_time : dt.datetime + Inclusive start of the window; must fall on an hour boundary + + company_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Restrict to these company IDs; omit for every company in the environment + + feature_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Restrict to these event features; omit for every event feature in the environment. Where several features measure the same event, each is reported separately and a page may carry more rows than the requested limit + + granularity : typing.Optional[TimeSeriesGranularity] + Bucket the window; omit for a single total per company and feature + + limit : typing.Optional[int] + Page limit (default 100) + + offset : typing.Optional[int] + Page offset (default 0) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ListFeatureUsageHistoryResponse + OK + + Examples + -------- + import asyncio + import datetime + + from schematic import AsyncSchematic + + client = AsyncSchematic( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.entitlements.list_feature_usage_history( + company_ids=["company_ids"], + end_time=datetime.datetime.fromisoformat( + "2024-01-15 09:30:00+00:00", + ), + feature_ids=["feature_ids"], + granularity="daily", + start_time=datetime.datetime.fromisoformat( + "2024-01-15 09:30:00+00:00", + ), + limit=1000000, + offset=1000000, + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.list_feature_usage_history( + end_time=end_time, + start_time=start_time, + company_ids=company_ids, + feature_ids=feature_ids, + granularity=granularity, + limit=limit, + offset=offset, + request_options=request_options, + ) + return _response.data + async def get_feature_usage_time_series( self, *, diff --git a/src/schematic/entitlements/raw_client.py b/src/schematic/entitlements/raw_client.py index 6816bf8..ae382b5 100644 --- a/src/schematic/entitlements/raw_client.py +++ b/src/schematic/entitlements/raw_client.py @@ -47,6 +47,7 @@ from .types.get_user_usage_detail_response import GetUserUsageDetailResponse from .types.list_company_overrides_response import ListCompanyOverridesResponse from .types.list_feature_companies_response import ListFeatureCompaniesResponse +from .types.list_feature_usage_history_response import ListFeatureUsageHistoryResponse from .types.list_feature_usage_response import ListFeatureUsageResponse from .types.list_feature_users_response import ListFeatureUsersResponse from .types.list_plan_entitlements_response import ListPlanEntitlementsResponse @@ -1225,6 +1226,142 @@ def list_feature_usage( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) + def list_feature_usage_history( + self, + *, + end_time: dt.datetime, + start_time: dt.datetime, + company_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + feature_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + granularity: typing.Optional[TimeSeriesGranularity] = None, + limit: typing.Optional[int] = None, + offset: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ListFeatureUsageHistoryResponse]: + """ + Parameters + ---------- + end_time : dt.datetime + Exclusive end of the window; must fall on an hour boundary + + start_time : dt.datetime + Inclusive start of the window; must fall on an hour boundary + + company_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Restrict to these company IDs; omit for every company in the environment + + feature_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Restrict to these event features; omit for every event feature in the environment. Where several features measure the same event, each is reported separately and a page may carry more rows than the requested limit + + granularity : typing.Optional[TimeSeriesGranularity] + Bucket the window; omit for a single total per company and feature + + limit : typing.Optional[int] + Page limit (default 100) + + offset : typing.Optional[int] + Page offset (default 0) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ListFeatureUsageHistoryResponse] + OK + """ + _response = self._client_wrapper.httpx_client.request( + "feature-usage-history", + method="GET", + params={ + "company_ids": company_ids, + "end_time": serialize_datetime(end_time), + "feature_ids": feature_ids, + "granularity": granularity, + "start_time": serialize_datetime(start_time), + "limit": limit, + "offset": offset, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ListFeatureUsageHistoryResponse, + parse_obj_as( + type_=ListFeatureUsageHistoryResponse, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_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 core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + def get_feature_usage_time_series( self, *, @@ -4586,6 +4723,142 @@ async def list_feature_usage( status_code=_response.status_code, headers=dict(_response.headers), body=_response_json ) + async def list_feature_usage_history( + self, + *, + end_time: dt.datetime, + start_time: dt.datetime, + company_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + feature_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + granularity: typing.Optional[TimeSeriesGranularity] = None, + limit: typing.Optional[int] = None, + offset: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ListFeatureUsageHistoryResponse]: + """ + Parameters + ---------- + end_time : dt.datetime + Exclusive end of the window; must fall on an hour boundary + + start_time : dt.datetime + Inclusive start of the window; must fall on an hour boundary + + company_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Restrict to these company IDs; omit for every company in the environment + + feature_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Restrict to these event features; omit for every event feature in the environment. Where several features measure the same event, each is reported separately and a page may carry more rows than the requested limit + + granularity : typing.Optional[TimeSeriesGranularity] + Bucket the window; omit for a single total per company and feature + + limit : typing.Optional[int] + Page limit (default 100) + + offset : typing.Optional[int] + Page offset (default 0) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[ListFeatureUsageHistoryResponse] + OK + """ + _response = await self._client_wrapper.httpx_client.request( + "feature-usage-history", + method="GET", + params={ + "company_ids": company_ids, + "end_time": serialize_datetime(end_time), + "feature_ids": feature_ids, + "granularity": granularity, + "start_time": serialize_datetime(start_time), + "limit": limit, + "offset": offset, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ListFeatureUsageHistoryResponse, + parse_obj_as( + type_=ListFeatureUsageHistoryResponse, # 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( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise ForbiddenError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 500: + raise InternalServerError( + headers=dict(_response.headers), + body=typing.cast( + types_api_error_ApiError, + parse_obj_as( + type_=types_api_error_ApiError, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise core_api_error_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 core_api_error_ApiError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response_json + ) + async def get_feature_usage_time_series( self, *, diff --git a/src/schematic/entitlements/types/__init__.py b/src/schematic/entitlements/types/__init__.py index ca38d5f..364c408 100644 --- a/src/schematic/entitlements/types/__init__.py +++ b/src/schematic/entitlements/types/__init__.py @@ -35,6 +35,8 @@ from .list_company_overrides_response import ListCompanyOverridesResponse from .list_feature_companies_params import ListFeatureCompaniesParams from .list_feature_companies_response import ListFeatureCompaniesResponse + from .list_feature_usage_history_params import ListFeatureUsageHistoryParams + from .list_feature_usage_history_response import ListFeatureUsageHistoryResponse from .list_feature_usage_params import ListFeatureUsageParams from .list_feature_usage_response import ListFeatureUsageResponse from .list_feature_users_params import ListFeatureUsersParams @@ -74,6 +76,8 @@ "ListCompanyOverridesResponse": ".list_company_overrides_response", "ListFeatureCompaniesParams": ".list_feature_companies_params", "ListFeatureCompaniesResponse": ".list_feature_companies_response", + "ListFeatureUsageHistoryParams": ".list_feature_usage_history_params", + "ListFeatureUsageHistoryResponse": ".list_feature_usage_history_response", "ListFeatureUsageParams": ".list_feature_usage_params", "ListFeatureUsageResponse": ".list_feature_usage_response", "ListFeatureUsersParams": ".list_feature_users_params", @@ -137,6 +141,8 @@ def __dir__(): "ListCompanyOverridesResponse", "ListFeatureCompaniesParams", "ListFeatureCompaniesResponse", + "ListFeatureUsageHistoryParams", + "ListFeatureUsageHistoryResponse", "ListFeatureUsageParams", "ListFeatureUsageResponse", "ListFeatureUsersParams", diff --git a/src/schematic/entitlements/types/list_feature_usage_history_params.py b/src/schematic/entitlements/types/list_feature_usage_history_params.py new file mode 100644 index 0000000..807e416 --- /dev/null +++ b/src/schematic/entitlements/types/list_feature_usage_history_params.py @@ -0,0 +1,58 @@ +# 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 +from ...types.time_series_granularity import TimeSeriesGranularity + + +class ListFeatureUsageHistoryParams(UniversalBaseModel): + """ + Input parameters + """ + + company_ids: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + Restrict to these company IDs; omit for every company in the environment + """ + + end_time: typing.Optional[dt.datetime] = pydantic.Field(default=None) + """ + Exclusive end of the window; must fall on an hour boundary + """ + + feature_ids: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + Restrict to these event features; omit for every event feature in the environment. Where several features measure the same event, each is reported separately and a page may carry more rows than the requested limit + """ + + granularity: typing.Optional[TimeSeriesGranularity] = pydantic.Field(default=None) + """ + Bucket the window; omit for a single total per company and feature + """ + + limit: typing.Optional[int] = pydantic.Field(default=None) + """ + Page limit (default 100) + """ + + offset: typing.Optional[int] = pydantic.Field(default=None) + """ + Page offset (default 0) + """ + + start_time: typing.Optional[dt.datetime] = pydantic.Field(default=None) + """ + Inclusive start of the window; must fall on an hour boundary + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/schematic/entitlements/types/list_feature_usage_history_response.py b/src/schematic/entitlements/types/list_feature_usage_history_response.py new file mode 100644 index 0000000..d84310b --- /dev/null +++ b/src/schematic/entitlements/types/list_feature_usage_history_response.py @@ -0,0 +1,25 @@ +# 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.feature_usage_history_response_data import FeatureUsageHistoryResponseData +from .list_feature_usage_history_params import ListFeatureUsageHistoryParams + + +class ListFeatureUsageHistoryResponse(UniversalBaseModel): + data: typing.List[FeatureUsageHistoryResponseData] + params: ListFeatureUsageHistoryParams = pydantic.Field() + """ + Input parameters + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/schematic/features/client.py b/src/schematic/features/client.py index 047f365..cf36e52 100644 --- a/src/schematic/features/client.py +++ b/src/schematic/features/client.py @@ -10,6 +10,7 @@ from ..types.create_or_update_rule_request_body import CreateOrUpdateRuleRequestBody from ..types.feature_lifecycle_phase import FeatureLifecyclePhase from ..types.feature_type import FeatureType +from ..types.preflight_request_body import PreflightRequestBody from .raw_client import AsyncRawFeaturesClient, RawFeaturesClient from .types.check_flag_response import CheckFlagResponse from .types.check_flags_bulk_response import CheckFlagsBulkResponse @@ -847,6 +848,7 @@ def check_flag( key: str, *, company: typing.Optional[typing.Dict[str, str]] = OMIT, + preflight: typing.Optional[PreflightRequestBody] = OMIT, user: typing.Optional[typing.Dict[str, str]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> CheckFlagResponse: @@ -858,6 +860,9 @@ def check_flag( company : typing.Optional[typing.Dict[str, str]] + preflight : typing.Optional[PreflightRequestBody] + Hypothetical usage to evaluate the flag against, for answering "would this action be allowed?" before performing it. Only supported when checking a single flag. Values are caller-asserted and can widen a verdict as well as narrow it, so do not forward untrusted input here when the result gates access. Only the flag value reflects the preflight; the entitlement and usage figures in the response are the company's current, unsimulated ones + user : typing.Optional[typing.Dict[str, str]] request_options : typing.Optional[RequestOptions] @@ -879,13 +884,16 @@ def check_flag( key="key", ) """ - _response = self._raw_client.check_flag(key, company=company, user=user, request_options=request_options) + _response = self._raw_client.check_flag( + key, company=company, preflight=preflight, user=user, request_options=request_options + ) return _response.data def check_flags( self, *, company: typing.Optional[typing.Dict[str, str]] = OMIT, + preflight: typing.Optional[PreflightRequestBody] = OMIT, user: typing.Optional[typing.Dict[str, str]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> CheckFlagsResponse: @@ -894,6 +902,9 @@ def check_flags( ---------- company : typing.Optional[typing.Dict[str, str]] + preflight : typing.Optional[PreflightRequestBody] + Hypothetical usage to evaluate the flag against, for answering "would this action be allowed?" before performing it. Only supported when checking a single flag. Values are caller-asserted and can widen a verdict as well as narrow it, so do not forward untrusted input here when the result gates access. Only the flag value reflects the preflight; the entitlement and usage figures in the response are the company's current, unsimulated ones + user : typing.Optional[typing.Dict[str, str]] request_options : typing.Optional[RequestOptions] @@ -913,7 +924,9 @@ def check_flags( ) client.features.check_flags() """ - _response = self._raw_client.check_flags(company=company, user=user, request_options=request_options) + _response = self._raw_client.check_flags( + company=company, preflight=preflight, user=user, request_options=request_options + ) return _response.data def check_flags_bulk( @@ -1924,6 +1937,7 @@ async def check_flag( key: str, *, company: typing.Optional[typing.Dict[str, str]] = OMIT, + preflight: typing.Optional[PreflightRequestBody] = OMIT, user: typing.Optional[typing.Dict[str, str]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> CheckFlagResponse: @@ -1935,6 +1949,9 @@ async def check_flag( company : typing.Optional[typing.Dict[str, str]] + preflight : typing.Optional[PreflightRequestBody] + Hypothetical usage to evaluate the flag against, for answering "would this action be allowed?" before performing it. Only supported when checking a single flag. Values are caller-asserted and can widen a verdict as well as narrow it, so do not forward untrusted input here when the result gates access. Only the flag value reflects the preflight; the entitlement and usage figures in the response are the company's current, unsimulated ones + user : typing.Optional[typing.Dict[str, str]] request_options : typing.Optional[RequestOptions] @@ -1964,13 +1981,16 @@ async def main() -> None: asyncio.run(main()) """ - _response = await self._raw_client.check_flag(key, company=company, user=user, request_options=request_options) + _response = await self._raw_client.check_flag( + key, company=company, preflight=preflight, user=user, request_options=request_options + ) return _response.data async def check_flags( self, *, company: typing.Optional[typing.Dict[str, str]] = OMIT, + preflight: typing.Optional[PreflightRequestBody] = OMIT, user: typing.Optional[typing.Dict[str, str]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> CheckFlagsResponse: @@ -1979,6 +1999,9 @@ async def check_flags( ---------- company : typing.Optional[typing.Dict[str, str]] + preflight : typing.Optional[PreflightRequestBody] + Hypothetical usage to evaluate the flag against, for answering "would this action be allowed?" before performing it. Only supported when checking a single flag. Values are caller-asserted and can widen a verdict as well as narrow it, so do not forward untrusted input here when the result gates access. Only the flag value reflects the preflight; the entitlement and usage figures in the response are the company's current, unsimulated ones + user : typing.Optional[typing.Dict[str, str]] request_options : typing.Optional[RequestOptions] @@ -2006,7 +2029,9 @@ async def main() -> None: asyncio.run(main()) """ - _response = await self._raw_client.check_flags(company=company, user=user, request_options=request_options) + _response = await self._raw_client.check_flags( + company=company, preflight=preflight, user=user, request_options=request_options + ) return _response.data async def check_flags_bulk( diff --git a/src/schematic/features/raw_client.py b/src/schematic/features/raw_client.py index ef082d6..5dd811a 100644 --- a/src/schematic/features/raw_client.py +++ b/src/schematic/features/raw_client.py @@ -23,6 +23,7 @@ from ..types.create_or_update_rule_request_body import CreateOrUpdateRuleRequestBody from ..types.feature_lifecycle_phase import FeatureLifecyclePhase from ..types.feature_type import FeatureType +from ..types.preflight_request_body import PreflightRequestBody from .types.check_flag_response import CheckFlagResponse from .types.check_flags_bulk_response import CheckFlagsBulkResponse from .types.check_flags_response import CheckFlagsResponse @@ -1701,6 +1702,7 @@ def check_flag( key: str, *, company: typing.Optional[typing.Dict[str, str]] = OMIT, + preflight: typing.Optional[PreflightRequestBody] = OMIT, user: typing.Optional[typing.Dict[str, str]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[CheckFlagResponse]: @@ -1712,6 +1714,9 @@ def check_flag( company : typing.Optional[typing.Dict[str, str]] + preflight : typing.Optional[PreflightRequestBody] + Hypothetical usage to evaluate the flag against, for answering "would this action be allowed?" before performing it. Only supported when checking a single flag. Values are caller-asserted and can widen a verdict as well as narrow it, so do not forward untrusted input here when the result gates access. Only the flag value reflects the preflight; the entitlement and usage figures in the response are the company's current, unsimulated ones + user : typing.Optional[typing.Dict[str, str]] request_options : typing.Optional[RequestOptions] @@ -1727,6 +1732,9 @@ def check_flag( method="POST", json={ "company": company, + "preflight": convert_and_respect_annotation_metadata( + object_=preflight, annotation=PreflightRequestBody, direction="write" + ), "user": user, }, headers={ @@ -1817,6 +1825,7 @@ def check_flags( self, *, company: typing.Optional[typing.Dict[str, str]] = OMIT, + preflight: typing.Optional[PreflightRequestBody] = OMIT, user: typing.Optional[typing.Dict[str, str]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[CheckFlagsResponse]: @@ -1825,6 +1834,9 @@ def check_flags( ---------- company : typing.Optional[typing.Dict[str, str]] + preflight : typing.Optional[PreflightRequestBody] + Hypothetical usage to evaluate the flag against, for answering "would this action be allowed?" before performing it. Only supported when checking a single flag. Values are caller-asserted and can widen a verdict as well as narrow it, so do not forward untrusted input here when the result gates access. Only the flag value reflects the preflight; the entitlement and usage figures in the response are the company's current, unsimulated ones + user : typing.Optional[typing.Dict[str, str]] request_options : typing.Optional[RequestOptions] @@ -1840,6 +1852,9 @@ def check_flags( method="POST", json={ "company": company, + "preflight": convert_and_respect_annotation_metadata( + object_=preflight, annotation=PreflightRequestBody, direction="write" + ), "user": user, }, headers={ @@ -3817,6 +3832,7 @@ async def check_flag( key: str, *, company: typing.Optional[typing.Dict[str, str]] = OMIT, + preflight: typing.Optional[PreflightRequestBody] = OMIT, user: typing.Optional[typing.Dict[str, str]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[CheckFlagResponse]: @@ -3828,6 +3844,9 @@ async def check_flag( company : typing.Optional[typing.Dict[str, str]] + preflight : typing.Optional[PreflightRequestBody] + Hypothetical usage to evaluate the flag against, for answering "would this action be allowed?" before performing it. Only supported when checking a single flag. Values are caller-asserted and can widen a verdict as well as narrow it, so do not forward untrusted input here when the result gates access. Only the flag value reflects the preflight; the entitlement and usage figures in the response are the company's current, unsimulated ones + user : typing.Optional[typing.Dict[str, str]] request_options : typing.Optional[RequestOptions] @@ -3843,6 +3862,9 @@ async def check_flag( method="POST", json={ "company": company, + "preflight": convert_and_respect_annotation_metadata( + object_=preflight, annotation=PreflightRequestBody, direction="write" + ), "user": user, }, headers={ @@ -3933,6 +3955,7 @@ async def check_flags( self, *, company: typing.Optional[typing.Dict[str, str]] = OMIT, + preflight: typing.Optional[PreflightRequestBody] = OMIT, user: typing.Optional[typing.Dict[str, str]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[CheckFlagsResponse]: @@ -3941,6 +3964,9 @@ async def check_flags( ---------- company : typing.Optional[typing.Dict[str, str]] + preflight : typing.Optional[PreflightRequestBody] + Hypothetical usage to evaluate the flag against, for answering "would this action be allowed?" before performing it. Only supported when checking a single flag. Values are caller-asserted and can widen a verdict as well as narrow it, so do not forward untrusted input here when the result gates access. Only the flag value reflects the preflight; the entitlement and usage figures in the response are the company's current, unsimulated ones + user : typing.Optional[typing.Dict[str, str]] request_options : typing.Optional[RequestOptions] @@ -3956,6 +3982,9 @@ async def check_flags( method="POST", json={ "company": company, + "preflight": convert_and_respect_annotation_metadata( + object_=preflight, annotation=PreflightRequestBody, direction="write" + ), "user": user, }, headers={ diff --git a/src/schematic/planbundle/client.py b/src/schematic/planbundle/client.py index 9b5e2fa..e04d732 100644 --- a/src/schematic/planbundle/client.py +++ b/src/schematic/planbundle/client.py @@ -37,23 +37,23 @@ def with_raw_response(self) -> RawPlanbundleClient: def create_custom_plan_bundle( self, *, + billing_product: UpsertBillingProductRequestBody, entitlements: typing.Sequence[PlanBundleEntitlementRequestBody], - billing_product: typing.Optional[UpsertBillingProductRequestBody] = OMIT, + plan: CreateCustomPlanBundlePlanRequestBody, credit_grants: typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] = OMIT, - plan: typing.Optional[CreateCustomPlanBundlePlanRequestBody] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> CreateCustomPlanBundleResponse: """ Parameters ---------- + billing_product : UpsertBillingProductRequestBody + entitlements : typing.Sequence[PlanBundleEntitlementRequestBody] - billing_product : typing.Optional[UpsertBillingProductRequestBody] + plan : CreateCustomPlanBundlePlanRequestBody credit_grants : typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] - plan : typing.Optional[CreateCustomPlanBundlePlanRequestBody] - request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -64,24 +64,37 @@ def create_custom_plan_bundle( Examples -------- - from schematic import PlanBundleEntitlementRequestBody, Schematic + from schematic import ( + CreateCustomPlanBundlePlanRequestBody, + PlanBundleEntitlementRequestBody, + Schematic, + UpsertBillingProductRequestBody, + ) client = Schematic( api_key="YOUR_API_KEY", ) client.planbundle.create_custom_plan_bundle( + billing_product=UpsertBillingProductRequestBody( + charge_type="free", + is_trialable=True, + ), entitlements=[ PlanBundleEntitlementRequestBody( action="create", ) ], + plan=CreateCustomPlanBundlePlanRequestBody( + company_id="company_id", + name="name", + ), ) """ _response = self._raw_client.create_custom_plan_bundle( - entitlements=entitlements, billing_product=billing_product, - credit_grants=credit_grants, + entitlements=entitlements, plan=plan, + credit_grants=credit_grants, request_options=request_options, ) return _response.data @@ -90,9 +103,9 @@ def create_plan_bundle( self, *, entitlements: typing.Sequence[PlanBundleEntitlementRequestBody], + plan: CreatePlanRequestBody, billing_product: typing.Optional[UpsertBillingProductRequestBody] = OMIT, credit_grants: typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] = OMIT, - plan: typing.Optional[CreatePlanRequestBody] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> CreatePlanBundleResponse: """ @@ -100,12 +113,12 @@ def create_plan_bundle( ---------- entitlements : typing.Sequence[PlanBundleEntitlementRequestBody] + plan : CreatePlanRequestBody + billing_product : typing.Optional[UpsertBillingProductRequestBody] credit_grants : typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] - plan : typing.Optional[CreatePlanRequestBody] - request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -116,7 +129,11 @@ def create_plan_bundle( Examples -------- - from schematic import PlanBundleEntitlementRequestBody, Schematic + from schematic import ( + CreatePlanRequestBody, + PlanBundleEntitlementRequestBody, + Schematic, + ) client = Schematic( api_key="YOUR_API_KEY", @@ -127,42 +144,46 @@ def create_plan_bundle( action="create", ) ], + plan=CreatePlanRequestBody( + name="name", + plan_type="plan", + ), ) """ _response = self._raw_client.create_plan_bundle( entitlements=entitlements, + plan=plan, billing_product=billing_product, credit_grants=credit_grants, - plan=plan, request_options=request_options, ) return _response.data def update_plan_bundle( self, - plan_bundle_id: str, + plan_id: str, *, entitlements: typing.Sequence[PlanBundleEntitlementRequestBody], + plan: UpdatePlanRequestBody, billing_product: typing.Optional[UpsertBillingProductRequestBody] = OMIT, credit_grants: typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] = OMIT, - plan: typing.Optional[UpdatePlanRequestBody] = OMIT, plan_version_id: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> UpdatePlanBundleResponse: """ Parameters ---------- - plan_bundle_id : str - plan_bundle_id + plan_id : str + plan_id entitlements : typing.Sequence[PlanBundleEntitlementRequestBody] + plan : UpdatePlanRequestBody + billing_product : typing.Optional[UpsertBillingProductRequestBody] credit_grants : typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] - plan : typing.Optional[UpdatePlanRequestBody] - plan_version_id : typing.Optional[str] request_options : typing.Optional[RequestOptions] @@ -175,26 +196,33 @@ def update_plan_bundle( Examples -------- - from schematic import PlanBundleEntitlementRequestBody, Schematic + from schematic import ( + PlanBundleEntitlementRequestBody, + Schematic, + UpdatePlanRequestBody, + ) client = Schematic( api_key="YOUR_API_KEY", ) client.planbundle.update_plan_bundle( - plan_bundle_id="plan_bundle_id", + plan_id="plan_id", entitlements=[ PlanBundleEntitlementRequestBody( action="create", ) ], + plan=UpdatePlanRequestBody( + name="name", + ), ) """ _response = self._raw_client.update_plan_bundle( - plan_bundle_id, + plan_id, entitlements=entitlements, + plan=plan, billing_product=billing_product, credit_grants=credit_grants, - plan=plan, plan_version_id=plan_version_id, request_options=request_options, ) @@ -219,23 +247,23 @@ def with_raw_response(self) -> AsyncRawPlanbundleClient: async def create_custom_plan_bundle( self, *, + billing_product: UpsertBillingProductRequestBody, entitlements: typing.Sequence[PlanBundleEntitlementRequestBody], - billing_product: typing.Optional[UpsertBillingProductRequestBody] = OMIT, + plan: CreateCustomPlanBundlePlanRequestBody, credit_grants: typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] = OMIT, - plan: typing.Optional[CreateCustomPlanBundlePlanRequestBody] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> CreateCustomPlanBundleResponse: """ Parameters ---------- + billing_product : UpsertBillingProductRequestBody + entitlements : typing.Sequence[PlanBundleEntitlementRequestBody] - billing_product : typing.Optional[UpsertBillingProductRequestBody] + plan : CreateCustomPlanBundlePlanRequestBody credit_grants : typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] - plan : typing.Optional[CreateCustomPlanBundlePlanRequestBody] - request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -248,7 +276,12 @@ async def create_custom_plan_bundle( -------- import asyncio - from schematic import AsyncSchematic, PlanBundleEntitlementRequestBody + from schematic import ( + AsyncSchematic, + CreateCustomPlanBundlePlanRequestBody, + PlanBundleEntitlementRequestBody, + UpsertBillingProductRequestBody, + ) client = AsyncSchematic( api_key="YOUR_API_KEY", @@ -257,21 +290,29 @@ async def create_custom_plan_bundle( async def main() -> None: await client.planbundle.create_custom_plan_bundle( + billing_product=UpsertBillingProductRequestBody( + charge_type="free", + is_trialable=True, + ), entitlements=[ PlanBundleEntitlementRequestBody( action="create", ) ], + plan=CreateCustomPlanBundlePlanRequestBody( + company_id="company_id", + name="name", + ), ) asyncio.run(main()) """ _response = await self._raw_client.create_custom_plan_bundle( - entitlements=entitlements, billing_product=billing_product, - credit_grants=credit_grants, + entitlements=entitlements, plan=plan, + credit_grants=credit_grants, request_options=request_options, ) return _response.data @@ -280,9 +321,9 @@ async def create_plan_bundle( self, *, entitlements: typing.Sequence[PlanBundleEntitlementRequestBody], + plan: CreatePlanRequestBody, billing_product: typing.Optional[UpsertBillingProductRequestBody] = OMIT, credit_grants: typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] = OMIT, - plan: typing.Optional[CreatePlanRequestBody] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> CreatePlanBundleResponse: """ @@ -290,12 +331,12 @@ async def create_plan_bundle( ---------- entitlements : typing.Sequence[PlanBundleEntitlementRequestBody] + plan : CreatePlanRequestBody + billing_product : typing.Optional[UpsertBillingProductRequestBody] credit_grants : typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] - plan : typing.Optional[CreatePlanRequestBody] - request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -308,7 +349,11 @@ async def create_plan_bundle( -------- import asyncio - from schematic import AsyncSchematic, PlanBundleEntitlementRequestBody + from schematic import ( + AsyncSchematic, + CreatePlanRequestBody, + PlanBundleEntitlementRequestBody, + ) client = AsyncSchematic( api_key="YOUR_API_KEY", @@ -322,6 +367,10 @@ async def main() -> None: action="create", ) ], + plan=CreatePlanRequestBody( + name="name", + plan_type="plan", + ), ) @@ -329,38 +378,38 @@ async def main() -> None: """ _response = await self._raw_client.create_plan_bundle( entitlements=entitlements, + plan=plan, billing_product=billing_product, credit_grants=credit_grants, - plan=plan, request_options=request_options, ) return _response.data async def update_plan_bundle( self, - plan_bundle_id: str, + plan_id: str, *, entitlements: typing.Sequence[PlanBundleEntitlementRequestBody], + plan: UpdatePlanRequestBody, billing_product: typing.Optional[UpsertBillingProductRequestBody] = OMIT, credit_grants: typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] = OMIT, - plan: typing.Optional[UpdatePlanRequestBody] = OMIT, plan_version_id: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> UpdatePlanBundleResponse: """ Parameters ---------- - plan_bundle_id : str - plan_bundle_id + plan_id : str + plan_id entitlements : typing.Sequence[PlanBundleEntitlementRequestBody] + plan : UpdatePlanRequestBody + billing_product : typing.Optional[UpsertBillingProductRequestBody] credit_grants : typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] - plan : typing.Optional[UpdatePlanRequestBody] - plan_version_id : typing.Optional[str] request_options : typing.Optional[RequestOptions] @@ -375,7 +424,11 @@ async def update_plan_bundle( -------- import asyncio - from schematic import AsyncSchematic, PlanBundleEntitlementRequestBody + from schematic import ( + AsyncSchematic, + PlanBundleEntitlementRequestBody, + UpdatePlanRequestBody, + ) client = AsyncSchematic( api_key="YOUR_API_KEY", @@ -384,23 +437,26 @@ async def update_plan_bundle( async def main() -> None: await client.planbundle.update_plan_bundle( - plan_bundle_id="plan_bundle_id", + plan_id="plan_id", entitlements=[ PlanBundleEntitlementRequestBody( action="create", ) ], + plan=UpdatePlanRequestBody( + name="name", + ), ) asyncio.run(main()) """ _response = await self._raw_client.update_plan_bundle( - plan_bundle_id, + plan_id, entitlements=entitlements, + plan=plan, billing_product=billing_product, credit_grants=credit_grants, - plan=plan, plan_version_id=plan_version_id, request_options=request_options, ) diff --git a/src/schematic/planbundle/raw_client.py b/src/schematic/planbundle/raw_client.py index 886efa9..331b99c 100644 --- a/src/schematic/planbundle/raw_client.py +++ b/src/schematic/planbundle/raw_client.py @@ -39,23 +39,23 @@ def __init__(self, *, client_wrapper: SyncClientWrapper): def create_custom_plan_bundle( self, *, + billing_product: UpsertBillingProductRequestBody, entitlements: typing.Sequence[PlanBundleEntitlementRequestBody], - billing_product: typing.Optional[UpsertBillingProductRequestBody] = OMIT, + plan: CreateCustomPlanBundlePlanRequestBody, credit_grants: typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] = OMIT, - plan: typing.Optional[CreateCustomPlanBundlePlanRequestBody] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[CreateCustomPlanBundleResponse]: """ Parameters ---------- + billing_product : UpsertBillingProductRequestBody + entitlements : typing.Sequence[PlanBundleEntitlementRequestBody] - billing_product : typing.Optional[UpsertBillingProductRequestBody] + plan : CreateCustomPlanBundlePlanRequestBody credit_grants : typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] - plan : typing.Optional[CreateCustomPlanBundlePlanRequestBody] - request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -173,9 +173,9 @@ def create_plan_bundle( self, *, entitlements: typing.Sequence[PlanBundleEntitlementRequestBody], + plan: CreatePlanRequestBody, billing_product: typing.Optional[UpsertBillingProductRequestBody] = OMIT, credit_grants: typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] = OMIT, - plan: typing.Optional[CreatePlanRequestBody] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[CreatePlanBundleResponse]: """ @@ -183,12 +183,12 @@ def create_plan_bundle( ---------- entitlements : typing.Sequence[PlanBundleEntitlementRequestBody] + plan : CreatePlanRequestBody + billing_product : typing.Optional[UpsertBillingProductRequestBody] credit_grants : typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] - plan : typing.Optional[CreatePlanRequestBody] - request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -304,29 +304,29 @@ def create_plan_bundle( def update_plan_bundle( self, - plan_bundle_id: str, + plan_id: str, *, entitlements: typing.Sequence[PlanBundleEntitlementRequestBody], + plan: UpdatePlanRequestBody, billing_product: typing.Optional[UpsertBillingProductRequestBody] = OMIT, credit_grants: typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] = OMIT, - plan: typing.Optional[UpdatePlanRequestBody] = OMIT, plan_version_id: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[UpdatePlanBundleResponse]: """ Parameters ---------- - plan_bundle_id : str - plan_bundle_id + plan_id : str + plan_id entitlements : typing.Sequence[PlanBundleEntitlementRequestBody] + plan : UpdatePlanRequestBody + billing_product : typing.Optional[UpsertBillingProductRequestBody] credit_grants : typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] - plan : typing.Optional[UpdatePlanRequestBody] - plan_version_id : typing.Optional[str] request_options : typing.Optional[RequestOptions] @@ -338,7 +338,7 @@ def update_plan_bundle( OK """ _response = self._client_wrapper.httpx_client.request( - f"plan-bundles/{encode_path_param(plan_bundle_id)}", + f"plan-bundles/{encode_path_param(plan_id)}", method="PUT", json={ "billing_product": convert_and_respect_annotation_metadata( @@ -451,23 +451,23 @@ def __init__(self, *, client_wrapper: AsyncClientWrapper): async def create_custom_plan_bundle( self, *, + billing_product: UpsertBillingProductRequestBody, entitlements: typing.Sequence[PlanBundleEntitlementRequestBody], - billing_product: typing.Optional[UpsertBillingProductRequestBody] = OMIT, + plan: CreateCustomPlanBundlePlanRequestBody, credit_grants: typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] = OMIT, - plan: typing.Optional[CreateCustomPlanBundlePlanRequestBody] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[CreateCustomPlanBundleResponse]: """ Parameters ---------- + billing_product : UpsertBillingProductRequestBody + entitlements : typing.Sequence[PlanBundleEntitlementRequestBody] - billing_product : typing.Optional[UpsertBillingProductRequestBody] + plan : CreateCustomPlanBundlePlanRequestBody credit_grants : typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] - plan : typing.Optional[CreateCustomPlanBundlePlanRequestBody] - request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -585,9 +585,9 @@ async def create_plan_bundle( self, *, entitlements: typing.Sequence[PlanBundleEntitlementRequestBody], + plan: CreatePlanRequestBody, billing_product: typing.Optional[UpsertBillingProductRequestBody] = OMIT, credit_grants: typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] = OMIT, - plan: typing.Optional[CreatePlanRequestBody] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[CreatePlanBundleResponse]: """ @@ -595,12 +595,12 @@ async def create_plan_bundle( ---------- entitlements : typing.Sequence[PlanBundleEntitlementRequestBody] + plan : CreatePlanRequestBody + billing_product : typing.Optional[UpsertBillingProductRequestBody] credit_grants : typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] - plan : typing.Optional[CreatePlanRequestBody] - request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -716,29 +716,29 @@ async def create_plan_bundle( async def update_plan_bundle( self, - plan_bundle_id: str, + plan_id: str, *, entitlements: typing.Sequence[PlanBundleEntitlementRequestBody], + plan: UpdatePlanRequestBody, billing_product: typing.Optional[UpsertBillingProductRequestBody] = OMIT, credit_grants: typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] = OMIT, - plan: typing.Optional[UpdatePlanRequestBody] = OMIT, plan_version_id: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[UpdatePlanBundleResponse]: """ Parameters ---------- - plan_bundle_id : str - plan_bundle_id + plan_id : str + plan_id entitlements : typing.Sequence[PlanBundleEntitlementRequestBody] + plan : UpdatePlanRequestBody + billing_product : typing.Optional[UpsertBillingProductRequestBody] credit_grants : typing.Optional[typing.Sequence[PlanBundleCreditGrantRequestBody]] - plan : typing.Optional[UpdatePlanRequestBody] - plan_version_id : typing.Optional[str] request_options : typing.Optional[RequestOptions] @@ -750,7 +750,7 @@ async def update_plan_bundle( OK """ _response = await self._client_wrapper.httpx_client.request( - f"plan-bundles/{encode_path_param(plan_bundle_id)}", + f"plan-bundles/{encode_path_param(plan_id)}", method="PUT", json={ "billing_product": convert_and_respect_annotation_metadata( diff --git a/src/schematic/plangroups/client.py b/src/schematic/plangroups/client.py index db82dcd..1d6f409 100644 --- a/src/schematic/plangroups/client.py +++ b/src/schematic/plangroups/client.py @@ -4,6 +4,7 @@ from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper from ..core.request_options import RequestOptions +from ..types.checkout_bundle_purchase_behavior import CheckoutBundlePurchaseBehavior from ..types.checkout_field_input import CheckoutFieldInput from ..types.compatible_plans import CompatiblePlans from ..types.custom_plan_config import CustomPlanConfig @@ -77,6 +78,7 @@ def create_plan_group( checkout_collect_address: bool, checkout_collect_email: bool, checkout_collect_phone: bool, + checkout_collect_tax_id: bool, enable_tax_collection: bool, opt_in_enabled: bool, ordered_add_ons: typing.Sequence[OrderedPlansInGroup], @@ -93,6 +95,7 @@ def create_plan_group( show_zero_price_as_free: bool, sync_customer_billing_details: bool, add_on_compatibilities: typing.Optional[typing.Sequence[CompatiblePlans]] = OMIT, + checkout_bundle_purchase_behavior: typing.Optional[CheckoutBundlePurchaseBehavior] = OMIT, custom_checkout_fields: typing.Optional[typing.Sequence[CheckoutFieldInput]] = OMIT, custom_plan_config: typing.Optional[CustomPlanConfig] = OMIT, custom_plan_id: typing.Optional[str] = OMIT, @@ -123,6 +126,8 @@ def create_plan_group( checkout_collect_phone : bool + checkout_collect_tax_id : bool + enable_tax_collection : bool opt_in_enabled : bool @@ -155,6 +160,8 @@ def create_plan_group( add_on_compatibilities : typing.Optional[typing.Sequence[CompatiblePlans]] + checkout_bundle_purchase_behavior : typing.Optional[CheckoutBundlePurchaseBehavior] + custom_checkout_fields : typing.Optional[typing.Sequence[CheckoutFieldInput]] custom_plan_config : typing.Optional[CustomPlanConfig] @@ -207,6 +214,7 @@ def create_plan_group( checkout_collect_address=True, checkout_collect_email=True, checkout_collect_phone=True, + checkout_collect_tax_id=True, enable_tax_collection=True, opt_in_enabled=True, ordered_add_ons=[ @@ -241,6 +249,7 @@ def create_plan_group( checkout_collect_address=checkout_collect_address, checkout_collect_email=checkout_collect_email, checkout_collect_phone=checkout_collect_phone, + checkout_collect_tax_id=checkout_collect_tax_id, enable_tax_collection=enable_tax_collection, opt_in_enabled=opt_in_enabled, ordered_add_ons=ordered_add_ons, @@ -257,6 +266,7 @@ def create_plan_group( show_zero_price_as_free=show_zero_price_as_free, sync_customer_billing_details=sync_customer_billing_details, add_on_compatibilities=add_on_compatibilities, + checkout_bundle_purchase_behavior=checkout_bundle_purchase_behavior, custom_checkout_fields=custom_checkout_fields, custom_plan_config=custom_plan_config, custom_plan_id=custom_plan_id, @@ -285,6 +295,7 @@ def update_plan_group( checkout_collect_address: bool, checkout_collect_email: bool, checkout_collect_phone: bool, + checkout_collect_tax_id: bool, enable_tax_collection: bool, opt_in_enabled: bool, ordered_add_ons: typing.Sequence[OrderedPlansInGroup], @@ -301,6 +312,7 @@ def update_plan_group( show_zero_price_as_free: bool, sync_customer_billing_details: bool, add_on_compatibilities: typing.Optional[typing.Sequence[CompatiblePlans]] = OMIT, + checkout_bundle_purchase_behavior: typing.Optional[CheckoutBundlePurchaseBehavior] = OMIT, custom_checkout_fields: typing.Optional[typing.Sequence[CheckoutFieldInput]] = OMIT, custom_plan_config: typing.Optional[CustomPlanConfig] = OMIT, custom_plan_id: typing.Optional[str] = OMIT, @@ -334,6 +346,8 @@ def update_plan_group( checkout_collect_phone : bool + checkout_collect_tax_id : bool + enable_tax_collection : bool opt_in_enabled : bool @@ -366,6 +380,8 @@ def update_plan_group( add_on_compatibilities : typing.Optional[typing.Sequence[CompatiblePlans]] + checkout_bundle_purchase_behavior : typing.Optional[CheckoutBundlePurchaseBehavior] + custom_checkout_fields : typing.Optional[typing.Sequence[CheckoutFieldInput]] custom_plan_config : typing.Optional[CustomPlanConfig] @@ -419,6 +435,7 @@ def update_plan_group( checkout_collect_address=True, checkout_collect_email=True, checkout_collect_phone=True, + checkout_collect_tax_id=True, enable_tax_collection=True, opt_in_enabled=True, ordered_add_ons=[ @@ -454,6 +471,7 @@ def update_plan_group( checkout_collect_address=checkout_collect_address, checkout_collect_email=checkout_collect_email, checkout_collect_phone=checkout_collect_phone, + checkout_collect_tax_id=checkout_collect_tax_id, enable_tax_collection=enable_tax_collection, opt_in_enabled=opt_in_enabled, ordered_add_ons=ordered_add_ons, @@ -470,6 +488,7 @@ def update_plan_group( show_zero_price_as_free=show_zero_price_as_free, sync_customer_billing_details=sync_customer_billing_details, add_on_compatibilities=add_on_compatibilities, + checkout_bundle_purchase_behavior=checkout_bundle_purchase_behavior, custom_checkout_fields=custom_checkout_fields, custom_plan_config=custom_plan_config, custom_plan_id=custom_plan_id, @@ -556,6 +575,7 @@ async def create_plan_group( checkout_collect_address: bool, checkout_collect_email: bool, checkout_collect_phone: bool, + checkout_collect_tax_id: bool, enable_tax_collection: bool, opt_in_enabled: bool, ordered_add_ons: typing.Sequence[OrderedPlansInGroup], @@ -572,6 +592,7 @@ async def create_plan_group( show_zero_price_as_free: bool, sync_customer_billing_details: bool, add_on_compatibilities: typing.Optional[typing.Sequence[CompatiblePlans]] = OMIT, + checkout_bundle_purchase_behavior: typing.Optional[CheckoutBundlePurchaseBehavior] = OMIT, custom_checkout_fields: typing.Optional[typing.Sequence[CheckoutFieldInput]] = OMIT, custom_plan_config: typing.Optional[CustomPlanConfig] = OMIT, custom_plan_id: typing.Optional[str] = OMIT, @@ -602,6 +623,8 @@ async def create_plan_group( checkout_collect_phone : bool + checkout_collect_tax_id : bool + enable_tax_collection : bool opt_in_enabled : bool @@ -634,6 +657,8 @@ async def create_plan_group( add_on_compatibilities : typing.Optional[typing.Sequence[CompatiblePlans]] + checkout_bundle_purchase_behavior : typing.Optional[CheckoutBundlePurchaseBehavior] + custom_checkout_fields : typing.Optional[typing.Sequence[CheckoutFieldInput]] custom_plan_config : typing.Optional[CustomPlanConfig] @@ -691,6 +716,7 @@ async def main() -> None: checkout_collect_address=True, checkout_collect_email=True, checkout_collect_phone=True, + checkout_collect_tax_id=True, enable_tax_collection=True, opt_in_enabled=True, ordered_add_ons=[ @@ -728,6 +754,7 @@ async def main() -> None: checkout_collect_address=checkout_collect_address, checkout_collect_email=checkout_collect_email, checkout_collect_phone=checkout_collect_phone, + checkout_collect_tax_id=checkout_collect_tax_id, enable_tax_collection=enable_tax_collection, opt_in_enabled=opt_in_enabled, ordered_add_ons=ordered_add_ons, @@ -744,6 +771,7 @@ async def main() -> None: show_zero_price_as_free=show_zero_price_as_free, sync_customer_billing_details=sync_customer_billing_details, add_on_compatibilities=add_on_compatibilities, + checkout_bundle_purchase_behavior=checkout_bundle_purchase_behavior, custom_checkout_fields=custom_checkout_fields, custom_plan_config=custom_plan_config, custom_plan_id=custom_plan_id, @@ -772,6 +800,7 @@ async def update_plan_group( checkout_collect_address: bool, checkout_collect_email: bool, checkout_collect_phone: bool, + checkout_collect_tax_id: bool, enable_tax_collection: bool, opt_in_enabled: bool, ordered_add_ons: typing.Sequence[OrderedPlansInGroup], @@ -788,6 +817,7 @@ async def update_plan_group( show_zero_price_as_free: bool, sync_customer_billing_details: bool, add_on_compatibilities: typing.Optional[typing.Sequence[CompatiblePlans]] = OMIT, + checkout_bundle_purchase_behavior: typing.Optional[CheckoutBundlePurchaseBehavior] = OMIT, custom_checkout_fields: typing.Optional[typing.Sequence[CheckoutFieldInput]] = OMIT, custom_plan_config: typing.Optional[CustomPlanConfig] = OMIT, custom_plan_id: typing.Optional[str] = OMIT, @@ -821,6 +851,8 @@ async def update_plan_group( checkout_collect_phone : bool + checkout_collect_tax_id : bool + enable_tax_collection : bool opt_in_enabled : bool @@ -853,6 +885,8 @@ async def update_plan_group( add_on_compatibilities : typing.Optional[typing.Sequence[CompatiblePlans]] + checkout_bundle_purchase_behavior : typing.Optional[CheckoutBundlePurchaseBehavior] + custom_checkout_fields : typing.Optional[typing.Sequence[CheckoutFieldInput]] custom_plan_config : typing.Optional[CustomPlanConfig] @@ -911,6 +945,7 @@ async def main() -> None: checkout_collect_address=True, checkout_collect_email=True, checkout_collect_phone=True, + checkout_collect_tax_id=True, enable_tax_collection=True, opt_in_enabled=True, ordered_add_ons=[ @@ -949,6 +984,7 @@ async def main() -> None: checkout_collect_address=checkout_collect_address, checkout_collect_email=checkout_collect_email, checkout_collect_phone=checkout_collect_phone, + checkout_collect_tax_id=checkout_collect_tax_id, enable_tax_collection=enable_tax_collection, opt_in_enabled=opt_in_enabled, ordered_add_ons=ordered_add_ons, @@ -965,6 +1001,7 @@ async def main() -> None: show_zero_price_as_free=show_zero_price_as_free, sync_customer_billing_details=sync_customer_billing_details, add_on_compatibilities=add_on_compatibilities, + checkout_bundle_purchase_behavior=checkout_bundle_purchase_behavior, custom_checkout_fields=custom_checkout_fields, custom_plan_config=custom_plan_config, custom_plan_id=custom_plan_id, diff --git a/src/schematic/plangroups/raw_client.py b/src/schematic/plangroups/raw_client.py index 543f303..74db09c 100644 --- a/src/schematic/plangroups/raw_client.py +++ b/src/schematic/plangroups/raw_client.py @@ -17,6 +17,7 @@ from ..errors.not_found_error import NotFoundError from ..errors.unauthorized_error import UnauthorizedError from ..types.api_error import ApiError as types_api_error_ApiError +from ..types.checkout_bundle_purchase_behavior import CheckoutBundlePurchaseBehavior from ..types.checkout_field_input import CheckoutFieldInput from ..types.compatible_plans import CompatiblePlans from ..types.custom_plan_config import CustomPlanConfig @@ -138,6 +139,7 @@ def create_plan_group( checkout_collect_address: bool, checkout_collect_email: bool, checkout_collect_phone: bool, + checkout_collect_tax_id: bool, enable_tax_collection: bool, opt_in_enabled: bool, ordered_add_ons: typing.Sequence[OrderedPlansInGroup], @@ -154,6 +156,7 @@ def create_plan_group( show_zero_price_as_free: bool, sync_customer_billing_details: bool, add_on_compatibilities: typing.Optional[typing.Sequence[CompatiblePlans]] = OMIT, + checkout_bundle_purchase_behavior: typing.Optional[CheckoutBundlePurchaseBehavior] = OMIT, custom_checkout_fields: typing.Optional[typing.Sequence[CheckoutFieldInput]] = OMIT, custom_plan_config: typing.Optional[CustomPlanConfig] = OMIT, custom_plan_id: typing.Optional[str] = OMIT, @@ -184,6 +187,8 @@ def create_plan_group( checkout_collect_phone : bool + checkout_collect_tax_id : bool + enable_tax_collection : bool opt_in_enabled : bool @@ -216,6 +221,8 @@ def create_plan_group( add_on_compatibilities : typing.Optional[typing.Sequence[CompatiblePlans]] + checkout_bundle_purchase_behavior : typing.Optional[CheckoutBundlePurchaseBehavior] + custom_checkout_fields : typing.Optional[typing.Sequence[CheckoutFieldInput]] custom_plan_config : typing.Optional[CustomPlanConfig] @@ -264,9 +271,11 @@ def create_plan_group( object_=add_on_compatibilities, annotation=typing.Sequence[CompatiblePlans], direction="write" ), "add_on_ids": add_on_ids, + "checkout_bundle_purchase_behavior": checkout_bundle_purchase_behavior, "checkout_collect_address": checkout_collect_address, "checkout_collect_email": checkout_collect_email, "checkout_collect_phone": checkout_collect_phone, + "checkout_collect_tax_id": checkout_collect_tax_id, "custom_checkout_fields": convert_and_respect_annotation_metadata( object_=custom_checkout_fields, annotation=typing.Sequence[CheckoutFieldInput], direction="write" ), @@ -401,6 +410,7 @@ def update_plan_group( checkout_collect_address: bool, checkout_collect_email: bool, checkout_collect_phone: bool, + checkout_collect_tax_id: bool, enable_tax_collection: bool, opt_in_enabled: bool, ordered_add_ons: typing.Sequence[OrderedPlansInGroup], @@ -417,6 +427,7 @@ def update_plan_group( show_zero_price_as_free: bool, sync_customer_billing_details: bool, add_on_compatibilities: typing.Optional[typing.Sequence[CompatiblePlans]] = OMIT, + checkout_bundle_purchase_behavior: typing.Optional[CheckoutBundlePurchaseBehavior] = OMIT, custom_checkout_fields: typing.Optional[typing.Sequence[CheckoutFieldInput]] = OMIT, custom_plan_config: typing.Optional[CustomPlanConfig] = OMIT, custom_plan_id: typing.Optional[str] = OMIT, @@ -450,6 +461,8 @@ def update_plan_group( checkout_collect_phone : bool + checkout_collect_tax_id : bool + enable_tax_collection : bool opt_in_enabled : bool @@ -482,6 +495,8 @@ def update_plan_group( add_on_compatibilities : typing.Optional[typing.Sequence[CompatiblePlans]] + checkout_bundle_purchase_behavior : typing.Optional[CheckoutBundlePurchaseBehavior] + custom_checkout_fields : typing.Optional[typing.Sequence[CheckoutFieldInput]] custom_plan_config : typing.Optional[CustomPlanConfig] @@ -530,9 +545,11 @@ def update_plan_group( object_=add_on_compatibilities, annotation=typing.Sequence[CompatiblePlans], direction="write" ), "add_on_ids": add_on_ids, + "checkout_bundle_purchase_behavior": checkout_bundle_purchase_behavior, "checkout_collect_address": checkout_collect_address, "checkout_collect_email": checkout_collect_email, "checkout_collect_phone": checkout_collect_phone, + "checkout_collect_tax_id": checkout_collect_tax_id, "custom_checkout_fields": convert_and_respect_annotation_metadata( object_=custom_checkout_fields, annotation=typing.Sequence[CheckoutFieldInput], direction="write" ), @@ -765,6 +782,7 @@ async def create_plan_group( checkout_collect_address: bool, checkout_collect_email: bool, checkout_collect_phone: bool, + checkout_collect_tax_id: bool, enable_tax_collection: bool, opt_in_enabled: bool, ordered_add_ons: typing.Sequence[OrderedPlansInGroup], @@ -781,6 +799,7 @@ async def create_plan_group( show_zero_price_as_free: bool, sync_customer_billing_details: bool, add_on_compatibilities: typing.Optional[typing.Sequence[CompatiblePlans]] = OMIT, + checkout_bundle_purchase_behavior: typing.Optional[CheckoutBundlePurchaseBehavior] = OMIT, custom_checkout_fields: typing.Optional[typing.Sequence[CheckoutFieldInput]] = OMIT, custom_plan_config: typing.Optional[CustomPlanConfig] = OMIT, custom_plan_id: typing.Optional[str] = OMIT, @@ -811,6 +830,8 @@ async def create_plan_group( checkout_collect_phone : bool + checkout_collect_tax_id : bool + enable_tax_collection : bool opt_in_enabled : bool @@ -843,6 +864,8 @@ async def create_plan_group( add_on_compatibilities : typing.Optional[typing.Sequence[CompatiblePlans]] + checkout_bundle_purchase_behavior : typing.Optional[CheckoutBundlePurchaseBehavior] + custom_checkout_fields : typing.Optional[typing.Sequence[CheckoutFieldInput]] custom_plan_config : typing.Optional[CustomPlanConfig] @@ -891,9 +914,11 @@ async def create_plan_group( object_=add_on_compatibilities, annotation=typing.Sequence[CompatiblePlans], direction="write" ), "add_on_ids": add_on_ids, + "checkout_bundle_purchase_behavior": checkout_bundle_purchase_behavior, "checkout_collect_address": checkout_collect_address, "checkout_collect_email": checkout_collect_email, "checkout_collect_phone": checkout_collect_phone, + "checkout_collect_tax_id": checkout_collect_tax_id, "custom_checkout_fields": convert_and_respect_annotation_metadata( object_=custom_checkout_fields, annotation=typing.Sequence[CheckoutFieldInput], direction="write" ), @@ -1028,6 +1053,7 @@ async def update_plan_group( checkout_collect_address: bool, checkout_collect_email: bool, checkout_collect_phone: bool, + checkout_collect_tax_id: bool, enable_tax_collection: bool, opt_in_enabled: bool, ordered_add_ons: typing.Sequence[OrderedPlansInGroup], @@ -1044,6 +1070,7 @@ async def update_plan_group( show_zero_price_as_free: bool, sync_customer_billing_details: bool, add_on_compatibilities: typing.Optional[typing.Sequence[CompatiblePlans]] = OMIT, + checkout_bundle_purchase_behavior: typing.Optional[CheckoutBundlePurchaseBehavior] = OMIT, custom_checkout_fields: typing.Optional[typing.Sequence[CheckoutFieldInput]] = OMIT, custom_plan_config: typing.Optional[CustomPlanConfig] = OMIT, custom_plan_id: typing.Optional[str] = OMIT, @@ -1077,6 +1104,8 @@ async def update_plan_group( checkout_collect_phone : bool + checkout_collect_tax_id : bool + enable_tax_collection : bool opt_in_enabled : bool @@ -1109,6 +1138,8 @@ async def update_plan_group( add_on_compatibilities : typing.Optional[typing.Sequence[CompatiblePlans]] + checkout_bundle_purchase_behavior : typing.Optional[CheckoutBundlePurchaseBehavior] + custom_checkout_fields : typing.Optional[typing.Sequence[CheckoutFieldInput]] custom_plan_config : typing.Optional[CustomPlanConfig] @@ -1157,9 +1188,11 @@ async def update_plan_group( object_=add_on_compatibilities, annotation=typing.Sequence[CompatiblePlans], direction="write" ), "add_on_ids": add_on_ids, + "checkout_bundle_purchase_behavior": checkout_bundle_purchase_behavior, "checkout_collect_address": checkout_collect_address, "checkout_collect_email": checkout_collect_email, "checkout_collect_phone": checkout_collect_phone, + "checkout_collect_tax_id": checkout_collect_tax_id, "custom_checkout_fields": convert_and_respect_annotation_metadata( object_=custom_checkout_fields, annotation=typing.Sequence[CheckoutFieldInput], direction="write" ), diff --git a/src/schematic/planmigrations/client.py b/src/schematic/planmigrations/client.py index e48f68f..d20ef8b 100644 --- a/src/schematic/planmigrations/client.py +++ b/src/schematic/planmigrations/client.py @@ -5,6 +5,7 @@ from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper from ..core.request_options import RequestOptions from ..types.migration_error_code import MigrationErrorCode +from ..types.migration_proration_behavior import MigrationProrationBehavior from ..types.plan_type import PlanType from ..types.plan_version_company_migration_status import PlanVersionCompanyMigrationStatus from ..types.plan_version_migration_status import PlanVersionMigrationStatus @@ -42,7 +43,7 @@ def with_raw_response(self) -> RawPlanmigrationsClient: def list_company_migrations( self, *, - migration_id: typing.Optional[str] = None, + migration_id: str, q: typing.Optional[str] = None, status: typing.Optional[PlanVersionCompanyMigrationStatus] = None, limit: typing.Optional[int] = None, @@ -52,7 +53,7 @@ def list_company_migrations( """ Parameters ---------- - migration_id : typing.Optional[str] + migration_id : str q : typing.Optional[str] @@ -128,7 +129,7 @@ def retry_company_migration( def count_company_migrations( self, *, - migration_id: typing.Optional[str] = None, + migration_id: str, q: typing.Optional[str] = None, status: typing.Optional[PlanVersionCompanyMigrationStatus] = None, limit: typing.Optional[int] = None, @@ -138,7 +139,7 @@ def count_company_migrations( """ Parameters ---------- - migration_id : typing.Optional[str] + migration_id : str q : typing.Optional[str] @@ -181,7 +182,7 @@ def count_company_migrations( def list_migrations( self, *, - plan_version_id: typing.Optional[str] = None, + plan_version_id: str, status: typing.Optional[PlanVersionMigrationStatus] = None, limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, @@ -190,7 +191,7 @@ def list_migrations( """ Parameters ---------- - plan_version_id : typing.Optional[str] + plan_version_id : str status : typing.Optional[PlanVersionMigrationStatus] @@ -230,32 +231,35 @@ def list_migrations( def create_migration( self, *, - company_ids: typing.Sequence[str], - excluded_company_ids: typing.Sequence[str], plan_id: str, plan_version_id_to: str, - plan_version_ids_from: typing.Sequence[str], strategy: PlanVersionMigrationStrategy, target_plan_type: PlanType, + company_ids: typing.Optional[typing.Sequence[str]] = OMIT, + excluded_company_ids: typing.Optional[typing.Sequence[str]] = OMIT, + plan_version_ids_from: typing.Optional[typing.Sequence[str]] = OMIT, + proration_behavior: typing.Optional[MigrationProrationBehavior] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> CreateMigrationResponse: """ Parameters ---------- - company_ids : typing.Sequence[str] - - excluded_company_ids : typing.Sequence[str] - plan_id : str plan_version_id_to : str - plan_version_ids_from : typing.Sequence[str] - strategy : PlanVersionMigrationStrategy target_plan_type : PlanType + company_ids : typing.Optional[typing.Sequence[str]] + + excluded_company_ids : typing.Optional[typing.Sequence[str]] + + plan_version_ids_from : typing.Optional[typing.Sequence[str]] + + proration_behavior : typing.Optional[MigrationProrationBehavior] + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -272,23 +276,21 @@ def create_migration( api_key="YOUR_API_KEY", ) client.planmigrations.create_migration( - company_ids=["company_ids"], - excluded_company_ids=["excluded_company_ids"], plan_id="plan_id", plan_version_id_to="plan_version_id_to", - plan_version_ids_from=["plan_version_ids_from"], strategy="immediate", target_plan_type="plan", ) """ _response = self._raw_client.create_migration( - company_ids=company_ids, - excluded_company_ids=excluded_company_ids, plan_id=plan_id, plan_version_id_to=plan_version_id_to, - plan_version_ids_from=plan_version_ids_from, strategy=strategy, target_plan_type=target_plan_type, + company_ids=company_ids, + excluded_company_ids=excluded_company_ids, + plan_version_ids_from=plan_version_ids_from, + proration_behavior=proration_behavior, request_options=request_options, ) return _response.data @@ -367,7 +369,7 @@ def retry_migration( def count_migrations( self, *, - plan_version_id: typing.Optional[str] = None, + plan_version_id: str, status: typing.Optional[PlanVersionMigrationStatus] = None, limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, @@ -376,7 +378,7 @@ def count_migrations( """ Parameters ---------- - plan_version_id : typing.Optional[str] + plan_version_id : str status : typing.Optional[PlanVersionMigrationStatus] @@ -416,23 +418,26 @@ def count_migrations( def preview_migration( self, *, - company_ids: typing.Sequence[str], plan_id: str, plan_version_id_to: str, target_plan_type: PlanType, + company_ids: typing.Optional[typing.Sequence[str]] = OMIT, + plan_version_ids_from: typing.Optional[typing.Sequence[str]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> PreviewMigrationResponse: """ Parameters ---------- - company_ids : typing.Sequence[str] - plan_id : str plan_version_id_to : str target_plan_type : PlanType + company_ids : typing.Optional[typing.Sequence[str]] + + plan_version_ids_from : typing.Optional[typing.Sequence[str]] + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -449,17 +454,17 @@ def preview_migration( api_key="YOUR_API_KEY", ) client.planmigrations.preview_migration( - company_ids=["company_ids"], plan_id="plan_id", plan_version_id_to="plan_version_id_to", target_plan_type="plan", ) """ _response = self._raw_client.preview_migration( - company_ids=company_ids, plan_id=plan_id, plan_version_id_to=plan_version_id_to, target_plan_type=target_plan_type, + company_ids=company_ids, + plan_version_ids_from=plan_version_ids_from, request_options=request_options, ) return _response.data @@ -483,7 +488,7 @@ def with_raw_response(self) -> AsyncRawPlanmigrationsClient: async def list_company_migrations( self, *, - migration_id: typing.Optional[str] = None, + migration_id: str, q: typing.Optional[str] = None, status: typing.Optional[PlanVersionCompanyMigrationStatus] = None, limit: typing.Optional[int] = None, @@ -493,7 +498,7 @@ async def list_company_migrations( """ Parameters ---------- - migration_id : typing.Optional[str] + migration_id : str q : typing.Optional[str] @@ -585,7 +590,7 @@ async def main() -> None: async def count_company_migrations( self, *, - migration_id: typing.Optional[str] = None, + migration_id: str, q: typing.Optional[str] = None, status: typing.Optional[PlanVersionCompanyMigrationStatus] = None, limit: typing.Optional[int] = None, @@ -595,7 +600,7 @@ async def count_company_migrations( """ Parameters ---------- - migration_id : typing.Optional[str] + migration_id : str q : typing.Optional[str] @@ -646,7 +651,7 @@ async def main() -> None: async def list_migrations( self, *, - plan_version_id: typing.Optional[str] = None, + plan_version_id: str, status: typing.Optional[PlanVersionMigrationStatus] = None, limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, @@ -655,7 +660,7 @@ async def list_migrations( """ Parameters ---------- - plan_version_id : typing.Optional[str] + plan_version_id : str status : typing.Optional[PlanVersionMigrationStatus] @@ -703,32 +708,35 @@ async def main() -> None: async def create_migration( self, *, - company_ids: typing.Sequence[str], - excluded_company_ids: typing.Sequence[str], plan_id: str, plan_version_id_to: str, - plan_version_ids_from: typing.Sequence[str], strategy: PlanVersionMigrationStrategy, target_plan_type: PlanType, + company_ids: typing.Optional[typing.Sequence[str]] = OMIT, + excluded_company_ids: typing.Optional[typing.Sequence[str]] = OMIT, + plan_version_ids_from: typing.Optional[typing.Sequence[str]] = OMIT, + proration_behavior: typing.Optional[MigrationProrationBehavior] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> CreateMigrationResponse: """ Parameters ---------- - company_ids : typing.Sequence[str] - - excluded_company_ids : typing.Sequence[str] - plan_id : str plan_version_id_to : str - plan_version_ids_from : typing.Sequence[str] - strategy : PlanVersionMigrationStrategy target_plan_type : PlanType + company_ids : typing.Optional[typing.Sequence[str]] + + excluded_company_ids : typing.Optional[typing.Sequence[str]] + + plan_version_ids_from : typing.Optional[typing.Sequence[str]] + + proration_behavior : typing.Optional[MigrationProrationBehavior] + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -750,11 +758,8 @@ async def create_migration( async def main() -> None: await client.planmigrations.create_migration( - company_ids=["company_ids"], - excluded_company_ids=["excluded_company_ids"], plan_id="plan_id", plan_version_id_to="plan_version_id_to", - plan_version_ids_from=["plan_version_ids_from"], strategy="immediate", target_plan_type="plan", ) @@ -763,13 +768,14 @@ async def main() -> None: asyncio.run(main()) """ _response = await self._raw_client.create_migration( - company_ids=company_ids, - excluded_company_ids=excluded_company_ids, plan_id=plan_id, plan_version_id_to=plan_version_id_to, - plan_version_ids_from=plan_version_ids_from, strategy=strategy, target_plan_type=target_plan_type, + company_ids=company_ids, + excluded_company_ids=excluded_company_ids, + plan_version_ids_from=plan_version_ids_from, + proration_behavior=proration_behavior, request_options=request_options, ) return _response.data @@ -864,7 +870,7 @@ async def main() -> None: async def count_migrations( self, *, - plan_version_id: typing.Optional[str] = None, + plan_version_id: str, status: typing.Optional[PlanVersionMigrationStatus] = None, limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, @@ -873,7 +879,7 @@ async def count_migrations( """ Parameters ---------- - plan_version_id : typing.Optional[str] + plan_version_id : str status : typing.Optional[PlanVersionMigrationStatus] @@ -921,23 +927,26 @@ async def main() -> None: async def preview_migration( self, *, - company_ids: typing.Sequence[str], plan_id: str, plan_version_id_to: str, target_plan_type: PlanType, + company_ids: typing.Optional[typing.Sequence[str]] = OMIT, + plan_version_ids_from: typing.Optional[typing.Sequence[str]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> PreviewMigrationResponse: """ Parameters ---------- - company_ids : typing.Sequence[str] - plan_id : str plan_version_id_to : str target_plan_type : PlanType + company_ids : typing.Optional[typing.Sequence[str]] + + plan_version_ids_from : typing.Optional[typing.Sequence[str]] + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -959,7 +968,6 @@ async def preview_migration( async def main() -> None: await client.planmigrations.preview_migration( - company_ids=["company_ids"], plan_id="plan_id", plan_version_id_to="plan_version_id_to", target_plan_type="plan", @@ -969,10 +977,11 @@ async def main() -> None: asyncio.run(main()) """ _response = await self._raw_client.preview_migration( - company_ids=company_ids, plan_id=plan_id, plan_version_id_to=plan_version_id_to, target_plan_type=target_plan_type, + company_ids=company_ids, + plan_version_ids_from=plan_version_ids_from, request_options=request_options, ) return _response.data diff --git a/src/schematic/planmigrations/raw_client.py b/src/schematic/planmigrations/raw_client.py index 97a1dfa..e61e1e8 100644 --- a/src/schematic/planmigrations/raw_client.py +++ b/src/schematic/planmigrations/raw_client.py @@ -17,6 +17,7 @@ from ..errors.unauthorized_error import UnauthorizedError from ..types.api_error import ApiError as types_api_error_ApiError from ..types.migration_error_code import MigrationErrorCode +from ..types.migration_proration_behavior import MigrationProrationBehavior from ..types.plan_type import PlanType from ..types.plan_version_company_migration_status import PlanVersionCompanyMigrationStatus from ..types.plan_version_migration_status import PlanVersionMigrationStatus @@ -43,7 +44,7 @@ def __init__(self, *, client_wrapper: SyncClientWrapper): def list_company_migrations( self, *, - migration_id: typing.Optional[str] = None, + migration_id: str, q: typing.Optional[str] = None, status: typing.Optional[PlanVersionCompanyMigrationStatus] = None, limit: typing.Optional[int] = None, @@ -53,7 +54,7 @@ def list_company_migrations( """ Parameters ---------- - migration_id : typing.Optional[str] + migration_id : str q : typing.Optional[str] @@ -266,7 +267,7 @@ def retry_company_migration( def count_company_migrations( self, *, - migration_id: typing.Optional[str] = None, + migration_id: str, q: typing.Optional[str] = None, status: typing.Optional[PlanVersionCompanyMigrationStatus] = None, limit: typing.Optional[int] = None, @@ -276,7 +277,7 @@ def count_company_migrations( """ Parameters ---------- - migration_id : typing.Optional[str] + migration_id : str q : typing.Optional[str] @@ -389,7 +390,7 @@ def count_company_migrations( def list_migrations( self, *, - plan_version_id: typing.Optional[str] = None, + plan_version_id: str, status: typing.Optional[PlanVersionMigrationStatus] = None, limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, @@ -398,7 +399,7 @@ def list_migrations( """ Parameters ---------- - plan_version_id : typing.Optional[str] + plan_version_id : str status : typing.Optional[PlanVersionMigrationStatus] @@ -508,32 +509,35 @@ def list_migrations( def create_migration( self, *, - company_ids: typing.Sequence[str], - excluded_company_ids: typing.Sequence[str], plan_id: str, plan_version_id_to: str, - plan_version_ids_from: typing.Sequence[str], strategy: PlanVersionMigrationStrategy, target_plan_type: PlanType, + company_ids: typing.Optional[typing.Sequence[str]] = OMIT, + excluded_company_ids: typing.Optional[typing.Sequence[str]] = OMIT, + plan_version_ids_from: typing.Optional[typing.Sequence[str]] = OMIT, + proration_behavior: typing.Optional[MigrationProrationBehavior] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[CreateMigrationResponse]: """ Parameters ---------- - company_ids : typing.Sequence[str] - - excluded_company_ids : typing.Sequence[str] - plan_id : str plan_version_id_to : str - plan_version_ids_from : typing.Sequence[str] - strategy : PlanVersionMigrationStrategy target_plan_type : PlanType + company_ids : typing.Optional[typing.Sequence[str]] + + excluded_company_ids : typing.Optional[typing.Sequence[str]] + + plan_version_ids_from : typing.Optional[typing.Sequence[str]] + + proration_behavior : typing.Optional[MigrationProrationBehavior] + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -551,6 +555,7 @@ def create_migration( "plan_id": plan_id, "plan_version_id_to": plan_version_id_to, "plan_version_ids_from": plan_version_ids_from, + "proration_behavior": proration_behavior, "strategy": strategy, "target_plan_type": target_plan_type, }, @@ -843,7 +848,7 @@ def retry_migration( def count_migrations( self, *, - plan_version_id: typing.Optional[str] = None, + plan_version_id: str, status: typing.Optional[PlanVersionMigrationStatus] = None, limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, @@ -852,7 +857,7 @@ def count_migrations( """ Parameters ---------- - plan_version_id : typing.Optional[str] + plan_version_id : str status : typing.Optional[PlanVersionMigrationStatus] @@ -962,23 +967,26 @@ def count_migrations( def preview_migration( self, *, - company_ids: typing.Sequence[str], plan_id: str, plan_version_id_to: str, target_plan_type: PlanType, + company_ids: typing.Optional[typing.Sequence[str]] = OMIT, + plan_version_ids_from: typing.Optional[typing.Sequence[str]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[PreviewMigrationResponse]: """ Parameters ---------- - company_ids : typing.Sequence[str] - plan_id : str plan_version_id_to : str target_plan_type : PlanType + company_ids : typing.Optional[typing.Sequence[str]] + + plan_version_ids_from : typing.Optional[typing.Sequence[str]] + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -994,6 +1002,7 @@ def preview_migration( "company_ids": company_ids, "plan_id": plan_id, "plan_version_id_to": plan_version_id_to, + "plan_version_ids_from": plan_version_ids_from, "target_plan_type": target_plan_type, }, headers={ @@ -1088,7 +1097,7 @@ def __init__(self, *, client_wrapper: AsyncClientWrapper): async def list_company_migrations( self, *, - migration_id: typing.Optional[str] = None, + migration_id: str, q: typing.Optional[str] = None, status: typing.Optional[PlanVersionCompanyMigrationStatus] = None, limit: typing.Optional[int] = None, @@ -1098,7 +1107,7 @@ async def list_company_migrations( """ Parameters ---------- - migration_id : typing.Optional[str] + migration_id : str q : typing.Optional[str] @@ -1311,7 +1320,7 @@ async def retry_company_migration( async def count_company_migrations( self, *, - migration_id: typing.Optional[str] = None, + migration_id: str, q: typing.Optional[str] = None, status: typing.Optional[PlanVersionCompanyMigrationStatus] = None, limit: typing.Optional[int] = None, @@ -1321,7 +1330,7 @@ async def count_company_migrations( """ Parameters ---------- - migration_id : typing.Optional[str] + migration_id : str q : typing.Optional[str] @@ -1434,7 +1443,7 @@ async def count_company_migrations( async def list_migrations( self, *, - plan_version_id: typing.Optional[str] = None, + plan_version_id: str, status: typing.Optional[PlanVersionMigrationStatus] = None, limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, @@ -1443,7 +1452,7 @@ async def list_migrations( """ Parameters ---------- - plan_version_id : typing.Optional[str] + plan_version_id : str status : typing.Optional[PlanVersionMigrationStatus] @@ -1553,32 +1562,35 @@ async def list_migrations( async def create_migration( self, *, - company_ids: typing.Sequence[str], - excluded_company_ids: typing.Sequence[str], plan_id: str, plan_version_id_to: str, - plan_version_ids_from: typing.Sequence[str], strategy: PlanVersionMigrationStrategy, target_plan_type: PlanType, + company_ids: typing.Optional[typing.Sequence[str]] = OMIT, + excluded_company_ids: typing.Optional[typing.Sequence[str]] = OMIT, + plan_version_ids_from: typing.Optional[typing.Sequence[str]] = OMIT, + proration_behavior: typing.Optional[MigrationProrationBehavior] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[CreateMigrationResponse]: """ Parameters ---------- - company_ids : typing.Sequence[str] - - excluded_company_ids : typing.Sequence[str] - plan_id : str plan_version_id_to : str - plan_version_ids_from : typing.Sequence[str] - strategy : PlanVersionMigrationStrategy target_plan_type : PlanType + company_ids : typing.Optional[typing.Sequence[str]] + + excluded_company_ids : typing.Optional[typing.Sequence[str]] + + plan_version_ids_from : typing.Optional[typing.Sequence[str]] + + proration_behavior : typing.Optional[MigrationProrationBehavior] + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1596,6 +1608,7 @@ async def create_migration( "plan_id": plan_id, "plan_version_id_to": plan_version_id_to, "plan_version_ids_from": plan_version_ids_from, + "proration_behavior": proration_behavior, "strategy": strategy, "target_plan_type": target_plan_type, }, @@ -1888,7 +1901,7 @@ async def retry_migration( async def count_migrations( self, *, - plan_version_id: typing.Optional[str] = None, + plan_version_id: str, status: typing.Optional[PlanVersionMigrationStatus] = None, limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, @@ -1897,7 +1910,7 @@ async def count_migrations( """ Parameters ---------- - plan_version_id : typing.Optional[str] + plan_version_id : str status : typing.Optional[PlanVersionMigrationStatus] @@ -2007,23 +2020,26 @@ async def count_migrations( async def preview_migration( self, *, - company_ids: typing.Sequence[str], plan_id: str, plan_version_id_to: str, target_plan_type: PlanType, + company_ids: typing.Optional[typing.Sequence[str]] = OMIT, + plan_version_ids_from: typing.Optional[typing.Sequence[str]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[PreviewMigrationResponse]: """ Parameters ---------- - company_ids : typing.Sequence[str] - plan_id : str plan_version_id_to : str target_plan_type : PlanType + company_ids : typing.Optional[typing.Sequence[str]] + + plan_version_ids_from : typing.Optional[typing.Sequence[str]] + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -2039,6 +2055,7 @@ async def preview_migration( "company_ids": company_ids, "plan_id": plan_id, "plan_version_id_to": plan_version_id_to, + "plan_version_ids_from": plan_version_ids_from, "target_plan_type": target_plan_type, }, headers={ diff --git a/src/schematic/plans/client.py b/src/schematic/plans/client.py index 368089f..6abab06 100644 --- a/src/schematic/plans/client.py +++ b/src/schematic/plans/client.py @@ -12,6 +12,8 @@ from ..types.custom_plan_billing_status import CustomPlanBillingStatus from ..types.customer_billing_address import CustomerBillingAddress from ..types.mark_custom_plan_billing_paid_request_body import MarkCustomPlanBillingPaidRequestBody +from ..types.migration_proration_behavior import MigrationProrationBehavior +from ..types.plan_billing_source import PlanBillingSource from ..types.plan_currency_price_request_body import PlanCurrencyPriceRequestBody from ..types.plan_icon import PlanIcon from ..types.plan_type import PlanType @@ -58,7 +60,7 @@ def with_raw_response(self) -> RawPlansClient: def update_company_plans( self, - company_plan_id: str, + company_id: str, *, add_on_ids: typing.Sequence[str], base_plan_id: typing.Optional[str] = OMIT, @@ -67,8 +69,8 @@ def update_company_plans( """ Parameters ---------- - company_plan_id : str - company_plan_id + company_id : str + company_id add_on_ids : typing.Sequence[str] @@ -90,12 +92,12 @@ def update_company_plans( api_key="YOUR_API_KEY", ) client.plans.update_company_plans( - company_plan_id="company_plan_id", + company_id="company_id", add_on_ids=["add_on_ids"], ) """ _response = self._raw_client.update_company_plans( - company_plan_id, add_on_ids=add_on_ids, base_plan_id=base_plan_id, request_options=request_options + company_id, add_on_ids=add_on_ids, base_plan_id=base_plan_id, request_options=request_options ) return _response.data @@ -104,6 +106,7 @@ def list_custom_plan_billings( *, company_id: typing.Optional[str] = None, plan_id: typing.Optional[str] = None, + plan_billing_source: typing.Optional[PlanBillingSource] = None, status: typing.Optional[CustomPlanBillingStatus] = None, statuses: typing.Optional[ typing.Union[CustomPlanBillingStatus, typing.Sequence[CustomPlanBillingStatus]] @@ -121,6 +124,9 @@ def list_custom_plan_billings( plan_id : typing.Optional[str] Filter by plan ID + plan_billing_source : typing.Optional[PlanBillingSource] + Filter by the flow that created the billing record. Defaults to custom_plan. + status : typing.Optional[CustomPlanBillingStatus] Filter by billing status @@ -151,6 +157,7 @@ def list_custom_plan_billings( client.plans.list_custom_plan_billings( company_id="company_id", plan_id="plan_id", + plan_billing_source="custom_plan", status="active", statuses=["active"], limit=1000000, @@ -160,6 +167,7 @@ def list_custom_plan_billings( _response = self._raw_client.list_custom_plan_billings( company_id=company_id, plan_id=plan_id, + plan_billing_source=plan_billing_source, status=status, statuses=statuses, limit=limit, @@ -267,9 +275,10 @@ def create_custom_plan( self, *, company_id: str, - description: str, name: str, copied_from_plan_id: typing.Optional[str] = OMIT, + copied_price_id: typing.Optional[str] = OMIT, + description: typing.Optional[str] = OMIT, icon: typing.Optional[PlanIcon] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> CreateCustomPlanResponse: @@ -278,12 +287,14 @@ def create_custom_plan( ---------- company_id : str - description : str - name : str copied_from_plan_id : typing.Optional[str] + copied_price_id : typing.Optional[str] + + description : typing.Optional[str] + icon : typing.Optional[PlanIcon] request_options : typing.Optional[RequestOptions] @@ -303,15 +314,15 @@ def create_custom_plan( ) client.plans.create_custom_plan( company_id="company_id", - description="description", name="name", ) """ _response = self._raw_client.create_custom_plan( company_id=company_id, - description=description, name=name, copied_from_plan_id=copied_from_plan_id, + copied_price_id=copied_price_id, + description=description, icon=icon, request_options=request_options, ) @@ -450,21 +461,21 @@ def list_plans( def create_plan( self, *, - description: str, name: str, plan_type: PlanType, + description: typing.Optional[str] = OMIT, icon: typing.Optional[PlanIcon] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> CreatePlanResponse: """ Parameters ---------- - description : str - name : str plan_type : PlanType + description : typing.Optional[str] + icon : typing.Optional[PlanIcon] request_options : typing.Optional[RequestOptions] @@ -483,13 +494,12 @@ def create_plan( api_key="YOUR_API_KEY", ) client.plans.create_plan( - description="description", name="name", plan_type="plan", ) """ _response = self._raw_client.create_plan( - description=description, name=name, plan_type=plan_type, icon=icon, request_options=request_options + name=name, plan_type=plan_type, description=description, icon=icon, request_options=request_options ) return _response.data @@ -712,10 +722,10 @@ def upsert_plan_for_billing_product( self, *, billing_provider: BillingProviderType, - description: str, external_resource_id: str, name: str, plan_type: PlanType, + description: typing.Optional[str] = OMIT, external_resource_version: typing.Optional[str] = OMIT, icon: typing.Optional[PlanIcon] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -725,14 +735,14 @@ def upsert_plan_for_billing_product( ---------- billing_provider : BillingProviderType - description : str - external_resource_id : str name : str plan_type : PlanType + description : typing.Optional[str] + external_resource_version : typing.Optional[str] icon : typing.Optional[PlanIcon] @@ -754,7 +764,6 @@ def upsert_plan_for_billing_product( ) client.plans.upsert_plan_for_billing_product( billing_provider="metronome", - description="description", external_resource_id="external_resource_id", name="name", plan_type="plan", @@ -762,10 +771,10 @@ def upsert_plan_for_billing_product( """ _response = self._raw_client.upsert_plan_for_billing_product( billing_provider=billing_provider, - description=description, external_resource_id=external_resource_id, name=name, plan_type=plan_type, + description=description, external_resource_version=external_resource_version, icon=icon, request_options=request_options, @@ -1045,7 +1054,7 @@ def list_plan_issues( def delete_plan_version( self, - plan_id: str, + plan_version_id: str, *, promote_archived_version: typing.Optional[bool] = None, request_options: typing.Optional[RequestOptions] = None, @@ -1053,8 +1062,8 @@ def delete_plan_version( """ Parameters ---------- - plan_id : str - plan_id + plan_version_id : str + plan_version_id promote_archived_version : typing.Optional[bool] @@ -1074,18 +1083,18 @@ def delete_plan_version( api_key="YOUR_API_KEY", ) client.plans.delete_plan_version( - plan_id="plan_id", + plan_version_id="plan_version_id", promote_archived_version=True, ) """ _response = self._raw_client.delete_plan_version( - plan_id, promote_archived_version=promote_archived_version, request_options=request_options + plan_version_id, promote_archived_version=promote_archived_version, request_options=request_options ) return _response.data def publish_plan_version( self, - plan_id: str, + plan_version_id: str, *, excluded_company_ids: typing.Sequence[str], migration_strategy: PlanVersionMigrationStrategy, @@ -1096,6 +1105,8 @@ def publish_plan_version( customer_email: typing.Optional[str] = OMIT, days_until_due: typing.Optional[int] = OMIT, phone: typing.Optional[str] = OMIT, + proration_behavior: typing.Optional[MigrationProrationBehavior] = OMIT, + require_no_migration: typing.Optional[bool] = OMIT, send_invoice: typing.Optional[bool] = OMIT, tax_id: typing.Optional[TaxIdInput] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -1103,8 +1114,8 @@ def publish_plan_version( """ Parameters ---------- - plan_id : str - plan_id + plan_version_id : str + plan_version_id excluded_company_ids : typing.Sequence[str] @@ -1124,6 +1135,11 @@ def publish_plan_version( phone : typing.Optional[str] + proration_behavior : typing.Optional[MigrationProrationBehavior] + + require_no_migration : typing.Optional[bool] + Refuse the publish if any company would be migrated onto the new version + send_invoice : typing.Optional[bool] Whether Stripe emails the invoice when it is finalized. Defaults to true. @@ -1145,13 +1161,13 @@ def publish_plan_version( api_key="YOUR_API_KEY", ) client.plans.publish_plan_version( - plan_id="plan_id", + plan_version_id="plan_version_id", excluded_company_ids=["excluded_company_ids"], migration_strategy="immediate", ) """ _response = self._raw_client.publish_plan_version( - plan_id, + plan_version_id, excluded_company_ids=excluded_company_ids, migration_strategy=migration_strategy, activation_strategy=activation_strategy, @@ -1161,6 +1177,8 @@ def publish_plan_version( customer_email=customer_email, days_until_due=days_until_due, phone=phone, + proration_behavior=proration_behavior, + require_no_migration=require_no_migration, send_invoice=send_invoice, tax_id=tax_id, request_options=request_options, @@ -1185,7 +1203,7 @@ def with_raw_response(self) -> AsyncRawPlansClient: async def update_company_plans( self, - company_plan_id: str, + company_id: str, *, add_on_ids: typing.Sequence[str], base_plan_id: typing.Optional[str] = OMIT, @@ -1194,8 +1212,8 @@ async def update_company_plans( """ Parameters ---------- - company_plan_id : str - company_plan_id + company_id : str + company_id add_on_ids : typing.Sequence[str] @@ -1222,7 +1240,7 @@ async def update_company_plans( async def main() -> None: await client.plans.update_company_plans( - company_plan_id="company_plan_id", + company_id="company_id", add_on_ids=["add_on_ids"], ) @@ -1230,7 +1248,7 @@ async def main() -> None: asyncio.run(main()) """ _response = await self._raw_client.update_company_plans( - company_plan_id, add_on_ids=add_on_ids, base_plan_id=base_plan_id, request_options=request_options + company_id, add_on_ids=add_on_ids, base_plan_id=base_plan_id, request_options=request_options ) return _response.data @@ -1239,6 +1257,7 @@ async def list_custom_plan_billings( *, company_id: typing.Optional[str] = None, plan_id: typing.Optional[str] = None, + plan_billing_source: typing.Optional[PlanBillingSource] = None, status: typing.Optional[CustomPlanBillingStatus] = None, statuses: typing.Optional[ typing.Union[CustomPlanBillingStatus, typing.Sequence[CustomPlanBillingStatus]] @@ -1256,6 +1275,9 @@ async def list_custom_plan_billings( plan_id : typing.Optional[str] Filter by plan ID + plan_billing_source : typing.Optional[PlanBillingSource] + Filter by the flow that created the billing record. Defaults to custom_plan. + status : typing.Optional[CustomPlanBillingStatus] Filter by billing status @@ -1291,6 +1313,7 @@ async def main() -> None: await client.plans.list_custom_plan_billings( company_id="company_id", plan_id="plan_id", + plan_billing_source="custom_plan", status="active", statuses=["active"], limit=1000000, @@ -1303,6 +1326,7 @@ async def main() -> None: _response = await self._raw_client.list_custom_plan_billings( company_id=company_id, plan_id=plan_id, + plan_billing_source=plan_billing_source, status=status, statuses=statuses, limit=limit, @@ -1426,9 +1450,10 @@ async def create_custom_plan( self, *, company_id: str, - description: str, name: str, copied_from_plan_id: typing.Optional[str] = OMIT, + copied_price_id: typing.Optional[str] = OMIT, + description: typing.Optional[str] = OMIT, icon: typing.Optional[PlanIcon] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> CreateCustomPlanResponse: @@ -1437,12 +1462,14 @@ async def create_custom_plan( ---------- company_id : str - description : str - name : str copied_from_plan_id : typing.Optional[str] + copied_price_id : typing.Optional[str] + + description : typing.Optional[str] + icon : typing.Optional[PlanIcon] request_options : typing.Optional[RequestOptions] @@ -1467,7 +1494,6 @@ async def create_custom_plan( async def main() -> None: await client.plans.create_custom_plan( company_id="company_id", - description="description", name="name", ) @@ -1476,9 +1502,10 @@ async def main() -> None: """ _response = await self._raw_client.create_custom_plan( company_id=company_id, - description=description, name=name, copied_from_plan_id=copied_from_plan_id, + copied_price_id=copied_price_id, + description=description, icon=icon, request_options=request_options, ) @@ -1625,21 +1652,21 @@ async def main() -> None: async def create_plan( self, *, - description: str, name: str, plan_type: PlanType, + description: typing.Optional[str] = OMIT, icon: typing.Optional[PlanIcon] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> CreatePlanResponse: """ Parameters ---------- - description : str - name : str plan_type : PlanType + description : typing.Optional[str] + icon : typing.Optional[PlanIcon] request_options : typing.Optional[RequestOptions] @@ -1663,7 +1690,6 @@ async def create_plan( async def main() -> None: await client.plans.create_plan( - description="description", name="name", plan_type="plan", ) @@ -1672,7 +1698,7 @@ async def main() -> None: asyncio.run(main()) """ _response = await self._raw_client.create_plan( - description=description, name=name, plan_type=plan_type, icon=icon, request_options=request_options + name=name, plan_type=plan_type, description=description, icon=icon, request_options=request_options ) return _response.data @@ -1929,10 +1955,10 @@ async def upsert_plan_for_billing_product( self, *, billing_provider: BillingProviderType, - description: str, external_resource_id: str, name: str, plan_type: PlanType, + description: typing.Optional[str] = OMIT, external_resource_version: typing.Optional[str] = OMIT, icon: typing.Optional[PlanIcon] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -1942,14 +1968,14 @@ async def upsert_plan_for_billing_product( ---------- billing_provider : BillingProviderType - description : str - external_resource_id : str name : str plan_type : PlanType + description : typing.Optional[str] + external_resource_version : typing.Optional[str] icon : typing.Optional[PlanIcon] @@ -1976,7 +2002,6 @@ async def upsert_plan_for_billing_product( async def main() -> None: await client.plans.upsert_plan_for_billing_product( billing_provider="metronome", - description="description", external_resource_id="external_resource_id", name="name", plan_type="plan", @@ -1987,10 +2012,10 @@ async def main() -> None: """ _response = await self._raw_client.upsert_plan_for_billing_product( billing_provider=billing_provider, - description=description, external_resource_id=external_resource_id, name=name, plan_type=plan_type, + description=description, external_resource_version=external_resource_version, icon=icon, request_options=request_options, @@ -2302,7 +2327,7 @@ async def main() -> None: async def delete_plan_version( self, - plan_id: str, + plan_version_id: str, *, promote_archived_version: typing.Optional[bool] = None, request_options: typing.Optional[RequestOptions] = None, @@ -2310,8 +2335,8 @@ async def delete_plan_version( """ Parameters ---------- - plan_id : str - plan_id + plan_version_id : str + plan_version_id promote_archived_version : typing.Optional[bool] @@ -2336,7 +2361,7 @@ async def delete_plan_version( async def main() -> None: await client.plans.delete_plan_version( - plan_id="plan_id", + plan_version_id="plan_version_id", promote_archived_version=True, ) @@ -2344,13 +2369,13 @@ async def main() -> None: asyncio.run(main()) """ _response = await self._raw_client.delete_plan_version( - plan_id, promote_archived_version=promote_archived_version, request_options=request_options + plan_version_id, promote_archived_version=promote_archived_version, request_options=request_options ) return _response.data async def publish_plan_version( self, - plan_id: str, + plan_version_id: str, *, excluded_company_ids: typing.Sequence[str], migration_strategy: PlanVersionMigrationStrategy, @@ -2361,6 +2386,8 @@ async def publish_plan_version( customer_email: typing.Optional[str] = OMIT, days_until_due: typing.Optional[int] = OMIT, phone: typing.Optional[str] = OMIT, + proration_behavior: typing.Optional[MigrationProrationBehavior] = OMIT, + require_no_migration: typing.Optional[bool] = OMIT, send_invoice: typing.Optional[bool] = OMIT, tax_id: typing.Optional[TaxIdInput] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -2368,8 +2395,8 @@ async def publish_plan_version( """ Parameters ---------- - plan_id : str - plan_id + plan_version_id : str + plan_version_id excluded_company_ids : typing.Sequence[str] @@ -2389,6 +2416,11 @@ async def publish_plan_version( phone : typing.Optional[str] + proration_behavior : typing.Optional[MigrationProrationBehavior] + + require_no_migration : typing.Optional[bool] + Refuse the publish if any company would be migrated onto the new version + send_invoice : typing.Optional[bool] Whether Stripe emails the invoice when it is finalized. Defaults to true. @@ -2415,7 +2447,7 @@ async def publish_plan_version( async def main() -> None: await client.plans.publish_plan_version( - plan_id="plan_id", + plan_version_id="plan_version_id", excluded_company_ids=["excluded_company_ids"], migration_strategy="immediate", ) @@ -2424,7 +2456,7 @@ async def main() -> None: asyncio.run(main()) """ _response = await self._raw_client.publish_plan_version( - plan_id, + plan_version_id, excluded_company_ids=excluded_company_ids, migration_strategy=migration_strategy, activation_strategy=activation_strategy, @@ -2434,6 +2466,8 @@ async def main() -> None: customer_email=customer_email, days_until_due=days_until_due, phone=phone, + proration_behavior=proration_behavior, + require_no_migration=require_no_migration, send_invoice=send_invoice, tax_id=tax_id, request_options=request_options, diff --git a/src/schematic/plans/raw_client.py b/src/schematic/plans/raw_client.py index 8fb2720..ea79dd8 100644 --- a/src/schematic/plans/raw_client.py +++ b/src/schematic/plans/raw_client.py @@ -25,6 +25,8 @@ from ..types.custom_plan_billing_status import CustomPlanBillingStatus from ..types.customer_billing_address import CustomerBillingAddress from ..types.mark_custom_plan_billing_paid_request_body import MarkCustomPlanBillingPaidRequestBody +from ..types.migration_proration_behavior import MigrationProrationBehavior +from ..types.plan_billing_source import PlanBillingSource from ..types.plan_currency_price_request_body import PlanCurrencyPriceRequestBody from ..types.plan_icon import PlanIcon from ..types.plan_type import PlanType @@ -60,7 +62,7 @@ def __init__(self, *, client_wrapper: SyncClientWrapper): def update_company_plans( self, - company_plan_id: str, + company_id: str, *, add_on_ids: typing.Sequence[str], base_plan_id: typing.Optional[str] = OMIT, @@ -69,8 +71,8 @@ def update_company_plans( """ Parameters ---------- - company_plan_id : str - company_plan_id + company_id : str + company_id add_on_ids : typing.Sequence[str] @@ -85,7 +87,7 @@ def update_company_plans( OK """ _response = self._client_wrapper.httpx_client.request( - f"company-plans/{encode_path_param(company_plan_id)}", + f"company-plans/{encode_path_param(company_id)}", method="PUT", json={ "add_on_ids": add_on_ids, @@ -180,6 +182,7 @@ def list_custom_plan_billings( *, company_id: typing.Optional[str] = None, plan_id: typing.Optional[str] = None, + plan_billing_source: typing.Optional[PlanBillingSource] = None, status: typing.Optional[CustomPlanBillingStatus] = None, statuses: typing.Optional[ typing.Union[CustomPlanBillingStatus, typing.Sequence[CustomPlanBillingStatus]] @@ -197,6 +200,9 @@ def list_custom_plan_billings( plan_id : typing.Optional[str] Filter by plan ID + plan_billing_source : typing.Optional[PlanBillingSource] + Filter by the flow that created the billing record. Defaults to custom_plan. + status : typing.Optional[CustomPlanBillingStatus] Filter by billing status @@ -223,6 +229,7 @@ def list_custom_plan_billings( params={ "company_id": company_id, "plan_id": plan_id, + "plan_billing_source": plan_billing_source, "status": status, "statuses": statuses, "limit": limit, @@ -549,9 +556,10 @@ def create_custom_plan( self, *, company_id: str, - description: str, name: str, copied_from_plan_id: typing.Optional[str] = OMIT, + copied_price_id: typing.Optional[str] = OMIT, + description: typing.Optional[str] = OMIT, icon: typing.Optional[PlanIcon] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[CreateCustomPlanResponse]: @@ -560,12 +568,14 @@ def create_custom_plan( ---------- company_id : str - description : str - name : str copied_from_plan_id : typing.Optional[str] + copied_price_id : typing.Optional[str] + + description : typing.Optional[str] + icon : typing.Optional[PlanIcon] request_options : typing.Optional[RequestOptions] @@ -582,6 +592,7 @@ def create_custom_plan( json={ "company_id": company_id, "copied_from_plan_id": copied_from_plan_id, + "copied_price_id": copied_price_id, "description": description, "icon": icon, "name": name, @@ -856,21 +867,21 @@ def list_plans( def create_plan( self, *, - description: str, name: str, plan_type: PlanType, + description: typing.Optional[str] = OMIT, icon: typing.Optional[PlanIcon] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[CreatePlanResponse]: """ Parameters ---------- - description : str - name : str plan_type : PlanType + description : typing.Optional[str] + icon : typing.Optional[PlanIcon] request_options : typing.Optional[RequestOptions] @@ -1469,10 +1480,10 @@ def upsert_plan_for_billing_product( self, *, billing_provider: BillingProviderType, - description: str, external_resource_id: str, name: str, plan_type: PlanType, + description: typing.Optional[str] = OMIT, external_resource_version: typing.Optional[str] = OMIT, icon: typing.Optional[PlanIcon] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -1482,14 +1493,14 @@ def upsert_plan_for_billing_product( ---------- billing_provider : BillingProviderType - description : str - external_resource_id : str name : str plan_type : PlanType + description : typing.Optional[str] + external_resource_version : typing.Optional[str] icon : typing.Optional[PlanIcon] @@ -2134,7 +2145,7 @@ def list_plan_issues( def delete_plan_version( self, - plan_id: str, + plan_version_id: str, *, promote_archived_version: typing.Optional[bool] = None, request_options: typing.Optional[RequestOptions] = None, @@ -2142,8 +2153,8 @@ def delete_plan_version( """ Parameters ---------- - plan_id : str - plan_id + plan_version_id : str + plan_version_id promote_archived_version : typing.Optional[bool] @@ -2156,7 +2167,7 @@ def delete_plan_version( OK """ _response = self._client_wrapper.httpx_client.request( - f"plans/version/{encode_path_param(plan_id)}", + f"plans/version/{encode_path_param(plan_version_id)}", method="DELETE", params={ "promote_archived_version": promote_archived_version, @@ -2243,7 +2254,7 @@ def delete_plan_version( def publish_plan_version( self, - plan_id: str, + plan_version_id: str, *, excluded_company_ids: typing.Sequence[str], migration_strategy: PlanVersionMigrationStrategy, @@ -2254,6 +2265,8 @@ def publish_plan_version( customer_email: typing.Optional[str] = OMIT, days_until_due: typing.Optional[int] = OMIT, phone: typing.Optional[str] = OMIT, + proration_behavior: typing.Optional[MigrationProrationBehavior] = OMIT, + require_no_migration: typing.Optional[bool] = OMIT, send_invoice: typing.Optional[bool] = OMIT, tax_id: typing.Optional[TaxIdInput] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -2261,8 +2274,8 @@ def publish_plan_version( """ Parameters ---------- - plan_id : str - plan_id + plan_version_id : str + plan_version_id excluded_company_ids : typing.Sequence[str] @@ -2282,6 +2295,11 @@ def publish_plan_version( phone : typing.Optional[str] + proration_behavior : typing.Optional[MigrationProrationBehavior] + + require_no_migration : typing.Optional[bool] + Refuse the publish if any company would be migrated onto the new version + send_invoice : typing.Optional[bool] Whether Stripe emails the invoice when it is finalized. Defaults to true. @@ -2296,7 +2314,7 @@ def publish_plan_version( OK """ _response = self._client_wrapper.httpx_client.request( - f"plans/version/{encode_path_param(plan_id)}/publish", + f"plans/version/{encode_path_param(plan_version_id)}/publish", method="PUT", json={ "activation_strategy": activation_strategy, @@ -2312,6 +2330,8 @@ def publish_plan_version( "excluded_company_ids": excluded_company_ids, "migration_strategy": migration_strategy, "phone": phone, + "proration_behavior": proration_behavior, + "require_no_migration": require_no_migration, "send_invoice": send_invoice, "tax_id": convert_and_respect_annotation_metadata( object_=tax_id, annotation=TaxIdInput, direction="write" @@ -2408,7 +2428,7 @@ def __init__(self, *, client_wrapper: AsyncClientWrapper): async def update_company_plans( self, - company_plan_id: str, + company_id: str, *, add_on_ids: typing.Sequence[str], base_plan_id: typing.Optional[str] = OMIT, @@ -2417,8 +2437,8 @@ async def update_company_plans( """ Parameters ---------- - company_plan_id : str - company_plan_id + company_id : str + company_id add_on_ids : typing.Sequence[str] @@ -2433,7 +2453,7 @@ async def update_company_plans( OK """ _response = await self._client_wrapper.httpx_client.request( - f"company-plans/{encode_path_param(company_plan_id)}", + f"company-plans/{encode_path_param(company_id)}", method="PUT", json={ "add_on_ids": add_on_ids, @@ -2528,6 +2548,7 @@ async def list_custom_plan_billings( *, company_id: typing.Optional[str] = None, plan_id: typing.Optional[str] = None, + plan_billing_source: typing.Optional[PlanBillingSource] = None, status: typing.Optional[CustomPlanBillingStatus] = None, statuses: typing.Optional[ typing.Union[CustomPlanBillingStatus, typing.Sequence[CustomPlanBillingStatus]] @@ -2545,6 +2566,9 @@ async def list_custom_plan_billings( plan_id : typing.Optional[str] Filter by plan ID + plan_billing_source : typing.Optional[PlanBillingSource] + Filter by the flow that created the billing record. Defaults to custom_plan. + status : typing.Optional[CustomPlanBillingStatus] Filter by billing status @@ -2571,6 +2595,7 @@ async def list_custom_plan_billings( params={ "company_id": company_id, "plan_id": plan_id, + "plan_billing_source": plan_billing_source, "status": status, "statuses": statuses, "limit": limit, @@ -2897,9 +2922,10 @@ async def create_custom_plan( self, *, company_id: str, - description: str, name: str, copied_from_plan_id: typing.Optional[str] = OMIT, + copied_price_id: typing.Optional[str] = OMIT, + description: typing.Optional[str] = OMIT, icon: typing.Optional[PlanIcon] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[CreateCustomPlanResponse]: @@ -2908,12 +2934,14 @@ async def create_custom_plan( ---------- company_id : str - description : str - name : str copied_from_plan_id : typing.Optional[str] + copied_price_id : typing.Optional[str] + + description : typing.Optional[str] + icon : typing.Optional[PlanIcon] request_options : typing.Optional[RequestOptions] @@ -2930,6 +2958,7 @@ async def create_custom_plan( json={ "company_id": company_id, "copied_from_plan_id": copied_from_plan_id, + "copied_price_id": copied_price_id, "description": description, "icon": icon, "name": name, @@ -3204,21 +3233,21 @@ async def list_plans( async def create_plan( self, *, - description: str, name: str, plan_type: PlanType, + description: typing.Optional[str] = OMIT, icon: typing.Optional[PlanIcon] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[CreatePlanResponse]: """ Parameters ---------- - description : str - name : str plan_type : PlanType + description : typing.Optional[str] + icon : typing.Optional[PlanIcon] request_options : typing.Optional[RequestOptions] @@ -3817,10 +3846,10 @@ async def upsert_plan_for_billing_product( self, *, billing_provider: BillingProviderType, - description: str, external_resource_id: str, name: str, plan_type: PlanType, + description: typing.Optional[str] = OMIT, external_resource_version: typing.Optional[str] = OMIT, icon: typing.Optional[PlanIcon] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -3830,14 +3859,14 @@ async def upsert_plan_for_billing_product( ---------- billing_provider : BillingProviderType - description : str - external_resource_id : str name : str plan_type : PlanType + description : typing.Optional[str] + external_resource_version : typing.Optional[str] icon : typing.Optional[PlanIcon] @@ -4482,7 +4511,7 @@ async def list_plan_issues( async def delete_plan_version( self, - plan_id: str, + plan_version_id: str, *, promote_archived_version: typing.Optional[bool] = None, request_options: typing.Optional[RequestOptions] = None, @@ -4490,8 +4519,8 @@ async def delete_plan_version( """ Parameters ---------- - plan_id : str - plan_id + plan_version_id : str + plan_version_id promote_archived_version : typing.Optional[bool] @@ -4504,7 +4533,7 @@ async def delete_plan_version( OK """ _response = await self._client_wrapper.httpx_client.request( - f"plans/version/{encode_path_param(plan_id)}", + f"plans/version/{encode_path_param(plan_version_id)}", method="DELETE", params={ "promote_archived_version": promote_archived_version, @@ -4591,7 +4620,7 @@ async def delete_plan_version( async def publish_plan_version( self, - plan_id: str, + plan_version_id: str, *, excluded_company_ids: typing.Sequence[str], migration_strategy: PlanVersionMigrationStrategy, @@ -4602,6 +4631,8 @@ async def publish_plan_version( customer_email: typing.Optional[str] = OMIT, days_until_due: typing.Optional[int] = OMIT, phone: typing.Optional[str] = OMIT, + proration_behavior: typing.Optional[MigrationProrationBehavior] = OMIT, + require_no_migration: typing.Optional[bool] = OMIT, send_invoice: typing.Optional[bool] = OMIT, tax_id: typing.Optional[TaxIdInput] = OMIT, request_options: typing.Optional[RequestOptions] = None, @@ -4609,8 +4640,8 @@ async def publish_plan_version( """ Parameters ---------- - plan_id : str - plan_id + plan_version_id : str + plan_version_id excluded_company_ids : typing.Sequence[str] @@ -4630,6 +4661,11 @@ async def publish_plan_version( phone : typing.Optional[str] + proration_behavior : typing.Optional[MigrationProrationBehavior] + + require_no_migration : typing.Optional[bool] + Refuse the publish if any company would be migrated onto the new version + send_invoice : typing.Optional[bool] Whether Stripe emails the invoice when it is finalized. Defaults to true. @@ -4644,7 +4680,7 @@ async def publish_plan_version( OK """ _response = await self._client_wrapper.httpx_client.request( - f"plans/version/{encode_path_param(plan_id)}/publish", + f"plans/version/{encode_path_param(plan_version_id)}/publish", method="PUT", json={ "activation_strategy": activation_strategy, @@ -4660,6 +4696,8 @@ async def publish_plan_version( "excluded_company_ids": excluded_company_ids, "migration_strategy": migration_strategy, "phone": phone, + "proration_behavior": proration_behavior, + "require_no_migration": require_no_migration, "send_invoice": send_invoice, "tax_id": convert_and_respect_annotation_metadata( object_=tax_id, annotation=TaxIdInput, direction="write" diff --git a/src/schematic/plans/types/list_custom_plan_billings_params.py b/src/schematic/plans/types/list_custom_plan_billings_params.py index c26c871..4545f0d 100644 --- a/src/schematic/plans/types/list_custom_plan_billings_params.py +++ b/src/schematic/plans/types/list_custom_plan_billings_params.py @@ -5,6 +5,7 @@ import pydantic from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel from ...types.custom_plan_billing_status import CustomPlanBillingStatus +from ...types.plan_billing_source import PlanBillingSource class ListCustomPlanBillingsParams(UniversalBaseModel): @@ -27,6 +28,11 @@ class ListCustomPlanBillingsParams(UniversalBaseModel): Page offset (default 0) """ + plan_billing_source: typing.Optional[PlanBillingSource] = pydantic.Field(default=None) + """ + Filter by the flow that created the billing record. Defaults to custom_plan. + """ + plan_id: typing.Optional[str] = pydantic.Field(default=None) """ Filter by plan ID diff --git a/src/schematic/types/__init__.py b/src/schematic/types/__init__.py index 5d7e08f..d2e72ba 100644 --- a/src/schematic/types/__init__.py +++ b/src/schematic/types/__init__.py @@ -20,6 +20,7 @@ from .audit_log_export_metadata import AuditLogExportMetadata from .audit_log_list_response_data import AuditLogListResponseData from .audit_log_response_data import AuditLogResponseData + from .billing_collection_method import BillingCollectionMethod from .billing_coupon_response_data import BillingCouponResponseData from .billing_credit_auto_topup_availability import BillingCreditAutoTopupAvailability from .billing_credit_bundle_response_data import BillingCreditBundleResponseData @@ -88,6 +89,7 @@ from .check_flag_response_data import CheckFlagResponseData from .check_flags_bulk_response_data import CheckFlagsBulkResponseData from .check_flags_response_data import CheckFlagsResponseData + from .checkout_bundle_purchase_behavior import CheckoutBundlePurchaseBehavior from .checkout_data_response_data import CheckoutDataResponseData from .checkout_field_input import CheckoutFieldInput from .checkout_field_response_data import CheckoutFieldResponseData @@ -221,6 +223,7 @@ from .entity_key_detail_response_data import EntityKeyDetailResponseData from .entity_key_response_data import EntityKeyResponseData from .entity_trait_definition_response_data import EntityTraitDefinitionResponseData + from .entity_trait_definition_usage import EntityTraitDefinitionUsage from .entity_trait_detail_response_data import EntityTraitDetailResponseData from .entity_trait_response_data import EntityTraitResponseData from .entity_trait_value import EntityTraitValue @@ -254,6 +257,7 @@ from .feature_response_data import FeatureResponseData from .feature_type import FeatureType from .feature_usage_detail_response_data import FeatureUsageDetailResponseData + from .feature_usage_history_response_data import FeatureUsageHistoryResponseData from .feature_usage_legacy_response_data import FeatureUsageLegacyResponseData from .feature_usage_response_data import FeatureUsageResponseData from .feature_usage_time_series_response_data import FeatureUsageTimeSeriesResponseData @@ -264,6 +268,7 @@ from .flag_type import FlagType from .flag_view import FlagView from .generic_preview_object import GenericPreviewObject + from .get_onboarding_state_resp import GetOnboardingStateResp from .insights_summary_response_data import InsightsSummaryResponseData from .install_integration_request_body import InstallIntegrationRequestBody from .integration_capabilities import IntegrationCapabilities @@ -300,11 +305,20 @@ from .metric_period_month_reset import MetricPeriodMonthReset from .metronome_integration_config import MetronomeIntegrationConfig from .migration_error_code import MigrationErrorCode + from .migration_proration_behavior import MigrationProrationBehavior from .mrr_response_data import MrrResponseData + from .onboarding_milestone import OnboardingMilestone + from .onboarding_milestone_view import OnboardingMilestoneView + from .onboarding_path import OnboardingPath + from .onboarding_requirement import OnboardingRequirement + from .onboarding_requirement_status import OnboardingRequirementStatus + from .onboarding_requirement_view import OnboardingRequirementView + from .onboarding_track import OnboardingTrack from .orb_integration_config import OrbIntegrationConfig from .ordered_plans_in_group import OrderedPlansInGroup from .payment_method_request_body import PaymentMethodRequestBody from .payment_method_response_data import PaymentMethodResponseData + from .plan_billing_source import PlanBillingSource from .plan_bundle_action import PlanBundleAction from .plan_bundle_credit_grant_request_body import PlanBundleCreditGrantRequestBody from .plan_bundle_entitlement_request_body import PlanBundleEntitlementRequestBody @@ -347,6 +361,8 @@ from .plan_version_snapshot_view import PlanVersionSnapshotView from .plan_version_status import PlanVersionStatus from .plan_view_public_response_data import PlanViewPublicResponseData + from .preflight_event_usage_request_body import PreflightEventUsageRequestBody + from .preflight_request_body import PreflightRequestBody from .preview_object import PreviewObject from .preview_object_response_data import PreviewObjectResponseData from .preview_subscription_change_response_data import PreviewSubscriptionChangeResponseData @@ -415,6 +431,7 @@ from .trait_definition_comparable_type import TraitDefinitionComparableType from .trait_type import TraitType from .trial_status import TrialStatus + from .upcoming_invoice_response_data import UpcomingInvoiceResponseData from .update_add_on_request_body import UpdateAddOnRequestBody from .update_auto_topup_override_request_body import UpdateAutoTopupOverrideRequestBody from .update_billing_plan_credit_grant_request_body import UpdateBillingPlanCreditGrantRequestBody @@ -469,6 +486,7 @@ "AuditLogExportMetadata": ".audit_log_export_metadata", "AuditLogListResponseData": ".audit_log_list_response_data", "AuditLogResponseData": ".audit_log_response_data", + "BillingCollectionMethod": ".billing_collection_method", "BillingCouponResponseData": ".billing_coupon_response_data", "BillingCreditAutoTopupAvailability": ".billing_credit_auto_topup_availability", "BillingCreditBundleResponseData": ".billing_credit_bundle_response_data", @@ -537,6 +555,7 @@ "CheckFlagResponseData": ".check_flag_response_data", "CheckFlagsBulkResponseData": ".check_flags_bulk_response_data", "CheckFlagsResponseData": ".check_flags_response_data", + "CheckoutBundlePurchaseBehavior": ".checkout_bundle_purchase_behavior", "CheckoutDataResponseData": ".checkout_data_response_data", "CheckoutFieldInput": ".checkout_field_input", "CheckoutFieldResponseData": ".checkout_field_response_data", @@ -664,6 +683,7 @@ "EntityKeyDetailResponseData": ".entity_key_detail_response_data", "EntityKeyResponseData": ".entity_key_response_data", "EntityTraitDefinitionResponseData": ".entity_trait_definition_response_data", + "EntityTraitDefinitionUsage": ".entity_trait_definition_usage", "EntityTraitDetailResponseData": ".entity_trait_detail_response_data", "EntityTraitResponseData": ".entity_trait_response_data", "EntityTraitValue": ".entity_trait_value", @@ -697,6 +717,7 @@ "FeatureResponseData": ".feature_response_data", "FeatureType": ".feature_type", "FeatureUsageDetailResponseData": ".feature_usage_detail_response_data", + "FeatureUsageHistoryResponseData": ".feature_usage_history_response_data", "FeatureUsageLegacyResponseData": ".feature_usage_legacy_response_data", "FeatureUsageResponseData": ".feature_usage_response_data", "FeatureUsageTimeSeriesResponseData": ".feature_usage_time_series_response_data", @@ -707,6 +728,7 @@ "FlagType": ".flag_type", "FlagView": ".flag_view", "GenericPreviewObject": ".generic_preview_object", + "GetOnboardingStateResp": ".get_onboarding_state_resp", "InsightsSummaryResponseData": ".insights_summary_response_data", "InstallIntegrationRequestBody": ".install_integration_request_body", "IntegrationCapabilities": ".integration_capabilities", @@ -741,11 +763,20 @@ "MetricPeriodMonthReset": ".metric_period_month_reset", "MetronomeIntegrationConfig": ".metronome_integration_config", "MigrationErrorCode": ".migration_error_code", + "MigrationProrationBehavior": ".migration_proration_behavior", "MrrResponseData": ".mrr_response_data", + "OnboardingMilestone": ".onboarding_milestone", + "OnboardingMilestoneView": ".onboarding_milestone_view", + "OnboardingPath": ".onboarding_path", + "OnboardingRequirement": ".onboarding_requirement", + "OnboardingRequirementStatus": ".onboarding_requirement_status", + "OnboardingRequirementView": ".onboarding_requirement_view", + "OnboardingTrack": ".onboarding_track", "OrbIntegrationConfig": ".orb_integration_config", "OrderedPlansInGroup": ".ordered_plans_in_group", "PaymentMethodRequestBody": ".payment_method_request_body", "PaymentMethodResponseData": ".payment_method_response_data", + "PlanBillingSource": ".plan_billing_source", "PlanBundleAction": ".plan_bundle_action", "PlanBundleCreditGrantRequestBody": ".plan_bundle_credit_grant_request_body", "PlanBundleEntitlementRequestBody": ".plan_bundle_entitlement_request_body", @@ -788,6 +819,8 @@ "PlanVersionSnapshotView": ".plan_version_snapshot_view", "PlanVersionStatus": ".plan_version_status", "PlanViewPublicResponseData": ".plan_view_public_response_data", + "PreflightEventUsageRequestBody": ".preflight_event_usage_request_body", + "PreflightRequestBody": ".preflight_request_body", "PreviewObject": ".preview_object", "PreviewObjectResponseData": ".preview_object_response_data", "PreviewSubscriptionChangeResponseData": ".preview_subscription_change_response_data", @@ -856,6 +889,7 @@ "TraitDefinitionComparableType": ".trait_definition_comparable_type", "TraitType": ".trait_type", "TrialStatus": ".trial_status", + "UpcomingInvoiceResponseData": ".upcoming_invoice_response_data", "UpdateAddOnRequestBody": ".update_add_on_request_body", "UpdateAutoTopupOverrideRequestBody": ".update_auto_topup_override_request_body", "UpdateBillingPlanCreditGrantRequestBody": ".update_billing_plan_credit_grant_request_body", @@ -934,6 +968,7 @@ def __dir__(): "AuditLogExportMetadata", "AuditLogListResponseData", "AuditLogResponseData", + "BillingCollectionMethod", "BillingCouponResponseData", "BillingCreditAutoTopupAvailability", "BillingCreditBundleResponseData", @@ -1002,6 +1037,7 @@ def __dir__(): "CheckFlagResponseData", "CheckFlagsBulkResponseData", "CheckFlagsResponseData", + "CheckoutBundlePurchaseBehavior", "CheckoutDataResponseData", "CheckoutFieldInput", "CheckoutFieldResponseData", @@ -1129,6 +1165,7 @@ def __dir__(): "EntityKeyDetailResponseData", "EntityKeyResponseData", "EntityTraitDefinitionResponseData", + "EntityTraitDefinitionUsage", "EntityTraitDetailResponseData", "EntityTraitResponseData", "EntityTraitValue", @@ -1162,6 +1199,7 @@ def __dir__(): "FeatureResponseData", "FeatureType", "FeatureUsageDetailResponseData", + "FeatureUsageHistoryResponseData", "FeatureUsageLegacyResponseData", "FeatureUsageResponseData", "FeatureUsageTimeSeriesResponseData", @@ -1172,6 +1210,7 @@ def __dir__(): "FlagType", "FlagView", "GenericPreviewObject", + "GetOnboardingStateResp", "InsightsSummaryResponseData", "InstallIntegrationRequestBody", "IntegrationCapabilities", @@ -1206,11 +1245,20 @@ def __dir__(): "MetricPeriodMonthReset", "MetronomeIntegrationConfig", "MigrationErrorCode", + "MigrationProrationBehavior", "MrrResponseData", + "OnboardingMilestone", + "OnboardingMilestoneView", + "OnboardingPath", + "OnboardingRequirement", + "OnboardingRequirementStatus", + "OnboardingRequirementView", + "OnboardingTrack", "OrbIntegrationConfig", "OrderedPlansInGroup", "PaymentMethodRequestBody", "PaymentMethodResponseData", + "PlanBillingSource", "PlanBundleAction", "PlanBundleCreditGrantRequestBody", "PlanBundleEntitlementRequestBody", @@ -1253,6 +1301,8 @@ def __dir__(): "PlanVersionSnapshotView", "PlanVersionStatus", "PlanViewPublicResponseData", + "PreflightEventUsageRequestBody", + "PreflightRequestBody", "PreviewObject", "PreviewObjectResponseData", "PreviewSubscriptionChangeResponseData", @@ -1321,6 +1371,7 @@ def __dir__(): "TraitDefinitionComparableType", "TraitType", "TrialStatus", + "UpcomingInvoiceResponseData", "UpdateAddOnRequestBody", "UpdateAutoTopupOverrideRequestBody", "UpdateBillingPlanCreditGrantRequestBody", diff --git a/src/schematic/types/audit_log_response_data.py b/src/schematic/types/audit_log_response_data.py index f1932ca..20d43e9 100644 --- a/src/schematic/types/audit_log_response_data.py +++ b/src/schematic/types/audit_log_response_data.py @@ -11,6 +11,7 @@ class AuditLogResponseData(UniversalBaseModel): + account_member_id: typing.Optional[str] = None actor_type: ActorType api_key: typing.Optional[ApiKeyResponseData] = None api_key_id: typing.Optional[str] = None diff --git a/src/schematic/types/billing_collection_method.py b/src/schematic/types/billing_collection_method.py new file mode 100644 index 0000000..2711de5 --- /dev/null +++ b/src/schematic/types/billing_collection_method.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +BillingCollectionMethod = typing.Union[typing.Literal["charge_automatically", "send_invoice"], typing.Any] diff --git a/src/schematic/types/billing_credit_bundle_response_data.py b/src/schematic/types/billing_credit_bundle_response_data.py index 6d6e07c..6e6e19f 100644 --- a/src/schematic/types/billing_credit_bundle_response_data.py +++ b/src/schematic/types/billing_credit_bundle_response_data.py @@ -16,6 +16,11 @@ class BillingCreditBundleResponseData(UniversalBaseModel): billing_invoice_id: typing.Optional[str] = None bundle_type: BillingCreditBundleType = "fixed" + compatible_plan_ids: typing.List[str] = pydantic.Field() + """ + Plans whose companies may purchase this bundle. Empty means the bundle is purchasable on every plan. + """ + created_at: dt.datetime credit_description: typing.Optional[str] = None credit_icon: typing.Optional[str] = None diff --git a/src/schematic/types/billing_credit_bundle_view.py b/src/schematic/types/billing_credit_bundle_view.py index 4554b25..fb6b8c4 100644 --- a/src/schematic/types/billing_credit_bundle_view.py +++ b/src/schematic/types/billing_credit_bundle_view.py @@ -15,6 +15,7 @@ class BillingCreditBundleView(UniversalBaseModel): bundle_type: BillingCreditBundleType = "fixed" + compatible_plan_ids: typing.List[str] created_at: dt.datetime credit_description: typing.Optional[str] = None credit_icon: typing.Optional[str] = None diff --git a/src/schematic/types/billing_credit_grant_response_data.py b/src/schematic/types/billing_credit_grant_response_data.py index 0042655..a66d918 100644 --- a/src/schematic/types/billing_credit_grant_response_data.py +++ b/src/schematic/types/billing_credit_grant_response_data.py @@ -14,6 +14,11 @@ class BillingCreditGrantResponseData(UniversalBaseModel): company_id: str + company_license_id: typing.Optional[str] = pydantic.Field(default=None) + """ + The license instance this grant was issued for. Set only when a per-license plan grant issued it; null on a plan's own grant. + """ + company_name: str created_at: dt.datetime credit_icon: typing.Optional[str] = None @@ -23,6 +28,11 @@ class BillingCreditGrantResponseData(UniversalBaseModel): expires_at: typing.Optional[dt.datetime] = None grant_reason: BillingCreditGrantReason id: str + license_name: typing.Optional[str] = pydantic.Field(default=None) + """ + Name of the license this grant was issued for, when it came from a per-license plan grant. + """ + plan_id: typing.Optional[str] = None plan_name: typing.Optional[str] = None price: typing.Optional[BillingPriceResponseData] = None diff --git a/src/schematic/types/billing_plan_credit_grant_response_data.py b/src/schematic/types/billing_plan_credit_grant_response_data.py index 5493b1c..091c276 100644 --- a/src/schematic/types/billing_plan_credit_grant_response_data.py +++ b/src/schematic/types/billing_plan_credit_grant_response_data.py @@ -37,7 +37,12 @@ class BillingPlanCreditGrantResponseData(UniversalBaseModel): auto_topup_threshold_percent: typing.Optional[int] = None can_buy_bundles: bool = pydantic.Field() """ - Whether buyers can purchase one-time credit bundles on this grant, independent of auto top-up availability. + Deprecated: bundle availability is a per-bundle plan compatibility set now; use compatible_plan_ids on credit bundles instead. + """ + + company_credit_amount: int = pydantic.Field() + """ + Credits granted once per company on top of the per-license amount. Always 0 when scaling is fixed. """ created_at: dt.datetime diff --git a/src/schematic/types/check_flag_request_body.py b/src/schematic/types/check_flag_request_body.py index b81c374..fd48214 100644 --- a/src/schematic/types/check_flag_request_body.py +++ b/src/schematic/types/check_flag_request_body.py @@ -4,10 +4,16 @@ import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .preflight_request_body import PreflightRequestBody class CheckFlagRequestBody(UniversalBaseModel): company: typing.Optional[typing.Dict[str, str]] = None + preflight: typing.Optional[PreflightRequestBody] = pydantic.Field(default=None) + """ + Hypothetical usage to evaluate the flag against, for answering "would this action be allowed?" before performing it. Only supported when checking a single flag. Values are caller-asserted and can widen a verdict as well as narrow it, so do not forward untrusted input here when the result gates access. Only the flag value reflects the preflight; the entitlement and usage figures in the response are the company's current, unsimulated ones + """ + user: typing.Optional[typing.Dict[str, str]] = None if IS_PYDANTIC_V2: diff --git a/src/schematic/types/checkout_bundle_purchase_behavior.py b/src/schematic/types/checkout_bundle_purchase_behavior.py new file mode 100644 index 0000000..22a7775 --- /dev/null +++ b/src/schematic/types/checkout_bundle_purchase_behavior.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +CheckoutBundlePurchaseBehavior = typing.Union[typing.Literal["individual", "quantity"], typing.Any] diff --git a/src/schematic/types/checkout_settings_response_data.py b/src/schematic/types/checkout_settings_response_data.py index 83d2af4..0aa5e92 100644 --- a/src/schematic/types/checkout_settings_response_data.py +++ b/src/schematic/types/checkout_settings_response_data.py @@ -4,12 +4,15 @@ import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .checkout_bundle_purchase_behavior import CheckoutBundlePurchaseBehavior class CheckoutSettingsResponseData(UniversalBaseModel): + bundle_purchase_behavior: CheckoutBundlePurchaseBehavior collect_address: bool collect_email: bool collect_phone: bool + collect_tax_id: bool opt_in_enabled: bool opt_in_text: typing.Optional[str] = None opt_in_title: typing.Optional[str] = None diff --git a/src/schematic/types/company_billing_checkout_settings.py b/src/schematic/types/company_billing_checkout_settings.py index 9896040..30127ab 100644 --- a/src/schematic/types/company_billing_checkout_settings.py +++ b/src/schematic/types/company_billing_checkout_settings.py @@ -10,6 +10,7 @@ class CompanyBillingCheckoutSettings(UniversalBaseModel): collect_address: bool collect_email: bool collect_phone: bool + collect_tax_id: bool if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/schematic/types/company_feature_usage_export_metadata.py b/src/schematic/types/company_feature_usage_export_metadata.py index c20498c..62dd0cc 100644 --- a/src/schematic/types/company_feature_usage_export_metadata.py +++ b/src/schematic/types/company_feature_usage_export_metadata.py @@ -23,6 +23,16 @@ class CompanyFeatureUsageExportMetadata(UniversalBaseModel): Restrict the export to companies with these billing credit type IDs """ + entity_key_definition_ids: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + Company key definition IDs to include as columns, one column per definition, mirroring the companies list + """ + + entity_trait_definition_ids: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + Company trait definition IDs to include as columns, one column per definition, mirroring the companies list + """ + feature_ids: typing.Optional[typing.List[str]] = pydantic.Field(default=None) """ Schematic feature IDs (starting with 'feat_') to include as usage columns; empty means no usage columns @@ -58,6 +68,11 @@ class CompanyFeatureUsageExportMetadata(UniversalBaseModel): Restrict the export to companies on this plan version ID """ + plan_version_unpublished: typing.Optional[bool] = pydantic.Field(default=None) + """ + Restrict the export to companies on a plan version that is no longer published + """ + q: typing.Optional[str] = pydantic.Field(default=None) """ Free-text search over company name and keys diff --git a/src/schematic/types/company_plan_credit_grant_view.py b/src/schematic/types/company_plan_credit_grant_view.py index 5f92a4b..69e4848 100644 --- a/src/schematic/types/company_plan_credit_grant_view.py +++ b/src/schematic/types/company_plan_credit_grant_view.py @@ -31,6 +31,7 @@ class CompanyPlanCreditGrantView(UniversalBaseModel): company_auto_topup_amount: typing.Optional[int] = None company_auto_topup_enabled: typing.Optional[bool] = None company_auto_topup_threshold_credits: typing.Optional[int] = None + company_credit_amount: int created_at: dt.datetime credit: typing.Optional[BillingCreditView] = None credit_amount: int diff --git a/src/schematic/types/component_checkout_settings.py b/src/schematic/types/component_checkout_settings.py index 5737cdd..0c2bdf3 100644 --- a/src/schematic/types/component_checkout_settings.py +++ b/src/schematic/types/component_checkout_settings.py @@ -4,13 +4,16 @@ import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .checkout_bundle_purchase_behavior import CheckoutBundlePurchaseBehavior from .proration_behavior import ProrationBehavior class ComponentCheckoutSettings(UniversalBaseModel): + bundle_purchase_behavior: CheckoutBundlePurchaseBehavior collect_address: bool collect_email: bool collect_phone: bool + collect_tax_id: bool proration_behavior: ProrationBehavior tax_collection_enabled: bool diff --git a/src/schematic/types/component_hydrate_response_data.py b/src/schematic/types/component_hydrate_response_data.py index 4fa5e3b..abaafbd 100644 --- a/src/schematic/types/component_hydrate_response_data.py +++ b/src/schematic/types/component_hydrate_response_data.py @@ -16,10 +16,10 @@ from .component_response_data import ComponentResponseData from .credit_company_grant_view import CreditCompanyGrantView from .feature_usage_detail_response_data import FeatureUsageDetailResponseData -from .invoice_response_data import InvoiceResponseData from .plan_detail_response_data import PlanDetailResponseData from .scheduled_downgrade_response_data import ScheduledDowngradeResponseData from .stripe_embed_info import StripeEmbedInfo +from .upcoming_invoice_response_data import UpcomingInvoiceResponseData from .usage_based_entitlement_response_data import UsageBasedEntitlementResponseData @@ -50,7 +50,7 @@ class ComponentHydrateResponseData(UniversalBaseModel): stripe_embed: typing.Optional[StripeEmbedInfo] = None subscription: typing.Optional[CompanySubscriptionResponseData] = None trial_payment_method_required: typing.Optional[bool] = None - upcoming_invoice: typing.Optional[InvoiceResponseData] = None + upcoming_invoice: typing.Optional[UpcomingInvoiceResponseData] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/schematic/types/component_preview_response_data.py b/src/schematic/types/component_preview_response_data.py index 6f6138f..8661c7c 100644 --- a/src/schematic/types/component_preview_response_data.py +++ b/src/schematic/types/component_preview_response_data.py @@ -20,6 +20,7 @@ from .plan_detail_response_data import PlanDetailResponseData from .scheduled_downgrade_response_data import ScheduledDowngradeResponseData from .stripe_embed_info import StripeEmbedInfo +from .upcoming_invoice_response_data import UpcomingInvoiceResponseData from .usage_based_entitlement_response_data import UsageBasedEntitlementResponseData @@ -51,7 +52,7 @@ class ComponentPreviewResponseData(UniversalBaseModel): stripe_embed: typing.Optional[StripeEmbedInfo] = None subscription: typing.Optional[CompanySubscriptionResponseData] = None trial_payment_method_required: typing.Optional[bool] = None - upcoming_invoice: typing.Optional[InvoiceResponseData] = None + upcoming_invoice: typing.Optional[UpcomingInvoiceResponseData] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/schematic/types/create_billing_plan_credit_grant_request_body.py b/src/schematic/types/create_billing_plan_credit_grant_request_body.py index 587b7d8..7fc726f 100644 --- a/src/schematic/types/create_billing_plan_credit_grant_request_body.py +++ b/src/schematic/types/create_billing_plan_credit_grant_request_body.py @@ -26,7 +26,16 @@ class CreateBillingPlanCreditGrantRequestBody(UniversalBaseModel): auto_topup_self_service: typing.Optional[bool] = None auto_topup_threshold_credits: typing.Optional[int] = None auto_topup_threshold_percent: typing.Optional[int] = None - can_buy_bundles: typing.Optional[bool] = None + can_buy_bundles: typing.Optional[bool] = pydantic.Field(default=None) + """ + Deprecated: use compatible_plan_ids on credit bundles instead. Still accepted; writes through to the credit's bundle compatibility. + """ + + company_credit_amount: typing.Optional[int] = pydantic.Field(default=None) + """ + Credits granted once per company on top of the per-license amount. Only valid when scaling is per_license. Defaults to 0. + """ + credit_amount: int credit_id: str expiry_type: typing.Optional[BillingCreditExpiryType] = None diff --git a/src/schematic/types/create_custom_plan_bundle_plan_request_body.py b/src/schematic/types/create_custom_plan_bundle_plan_request_body.py index df86367..10e8a83 100644 --- a/src/schematic/types/create_custom_plan_bundle_plan_request_body.py +++ b/src/schematic/types/create_custom_plan_bundle_plan_request_body.py @@ -9,7 +9,7 @@ class CreateCustomPlanBundlePlanRequestBody(UniversalBaseModel): company_id: str - description: str + description: typing.Optional[str] = None icon: typing.Optional[PlanIcon] = None name: str diff --git a/src/schematic/types/create_plan_request_body.py b/src/schematic/types/create_plan_request_body.py index 9fe08f1..f47bde7 100644 --- a/src/schematic/types/create_plan_request_body.py +++ b/src/schematic/types/create_plan_request_body.py @@ -9,7 +9,7 @@ class CreatePlanRequestBody(UniversalBaseModel): - description: str + description: typing.Optional[str] = None icon: typing.Optional[PlanIcon] = None name: str plan_type: PlanType diff --git a/src/schematic/types/credit_company_grant_view.py b/src/schematic/types/credit_company_grant_view.py index 3b4db6e..1a1ea0b 100644 --- a/src/schematic/types/credit_company_grant_view.py +++ b/src/schematic/types/credit_company_grant_view.py @@ -18,6 +18,7 @@ class CreditCompanyGrantView(UniversalBaseModel): billing_credit_bundle_id: typing.Optional[str] = None billing_credit_id: str company_id: str + company_license_id: typing.Optional[str] = None company_name: str created_at: dt.datetime credit_description: str @@ -31,6 +32,7 @@ class CreditCompanyGrantView(UniversalBaseModel): expiry_unit_count: typing.Optional[int] = None grant_reason: BillingCreditGrantReason id: str + license_name: typing.Optional[str] = None plan_id: typing.Optional[str] = None plan_name: typing.Optional[str] = None plural_name: typing.Optional[str] = None diff --git a/src/schematic/types/custom_plan_billing_response_data.py b/src/schematic/types/custom_plan_billing_response_data.py index c4cf816..40e3300 100644 --- a/src/schematic/types/custom_plan_billing_response_data.py +++ b/src/schematic/types/custom_plan_billing_response_data.py @@ -7,16 +7,27 @@ from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel from .custom_plan_activation_strategy import CustomPlanActivationStrategy from .custom_plan_billing_status import CustomPlanBillingStatus +from .plan_billing_source import PlanBillingSource class CustomPlanBillingResponseData(UniversalBaseModel): activation_strategy: CustomPlanActivationStrategy + billing_cycle_anchor: typing.Optional[dt.datetime] = pydantic.Field(default=None) + """ + The billing period renewal date pinned when the subscription started, when one was set. When no invoice exists yet, the first invoice is raised on this date. + """ + company_id: str created_at: dt.datetime days_until_due: int external_invoice_id: typing.Optional[str] = None id: str paid_at: typing.Optional[dt.datetime] = None + plan_billing_source: PlanBillingSource = pydantic.Field() + """ + The flow that created this billing record: a custom plan, or a standard plan assigned by invoice through Manage Plan. + """ + plan_id: str published_at: typing.Optional[dt.datetime] = None send_invoice: bool diff --git a/src/schematic/types/data_export_metadata.py b/src/schematic/types/data_export_metadata.py index 1345091..7667818 100644 --- a/src/schematic/types/data_export_metadata.py +++ b/src/schematic/types/data_export_metadata.py @@ -39,6 +39,8 @@ class DataExportMetadata_CompanyFeatureUsage(UniversalBaseModel): export_type: typing.Literal["company-feature-usage"] = "company-feature-usage" company_ids: typing.Optional[typing.List[str]] = None credit_type_ids: typing.Optional[typing.List[str]] = None + entity_key_definition_ids: typing.Optional[typing.List[str]] = None + entity_trait_definition_ids: typing.Optional[typing.List[str]] = None feature_ids: typing.Optional[typing.List[str]] = None has_scheduled_downgrade: typing.Optional[bool] = None monetized_subscriptions: typing.Optional[bool] = None @@ -46,6 +48,7 @@ class DataExportMetadata_CompanyFeatureUsage(UniversalBaseModel): plan_id: typing.Optional[str] = None plan_ids: typing.Optional[typing.List[str]] = None plan_version_id: typing.Optional[str] = None + plan_version_unpublished: typing.Optional[bool] = None q: typing.Optional[str] = None sort_order_column: typing.Optional[str] = None sort_order_direction: typing.Optional[CompanyFeatureUsageExportMetadataSortOrderDirection] = None diff --git a/src/schematic/types/entity_trait_definition_usage.py b/src/schematic/types/entity_trait_definition_usage.py new file mode 100644 index 0000000..9014deb --- /dev/null +++ b/src/schematic/types/entity_trait_definition_usage.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 + + +class EntityTraitDefinitionUsage(UniversalBaseModel): + checkout_field_config_count: int + company_override_count: int + feature_count: int + plan_entitlement_count: int + plan_trait_count: int + rule_condition_count: int + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/schematic/types/event_body_flag_check.py b/src/schematic/types/event_body_flag_check.py index 9683528..10182cd 100644 --- a/src/schematic/types/event_body_flag_check.py +++ b/src/schematic/types/event_body_flag_check.py @@ -27,6 +27,11 @@ class EventBodyFlagCheck(UniversalBaseModel): The key of the flag being checked """ + preflight: typing.Optional[bool] = pydantic.Field(default=None) + """ + Whether the check was a preflight, asking whether an action would be allowed rather than reporting one that happened. Absent on ordinary checks + """ + reason: str = pydantic.Field() """ The reason why the value was returned diff --git a/src/schematic/types/feature_usage_history_response_data.py b/src/schematic/types/feature_usage_history_response_data.py new file mode 100644 index 0000000..d0cfeb4 --- /dev/null +++ b/src/schematic/types/feature_usage_history_response_data.py @@ -0,0 +1,40 @@ +# 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 FeatureUsageHistoryResponseData(UniversalBaseModel): + company_id: str = pydantic.Field() + """ + Companies are identified by ID only. To report against your own identifiers, resolve them once via the companies API and cache the mapping; keys are not repeated on every row. + """ + + event_subtype: str + feature_id: str + period_end: dt.datetime = pydantic.Field() + """ + Exclusive end of the period this usage covers + """ + + period_start: dt.datetime = pydantic.Field() + """ + Inclusive start of the period this usage covers + """ + + usage: int = pydantic.Field() + """ + Usage recorded within this period; an incremental total, not a running one + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/schematic/types/get_onboarding_state_resp.py b/src/schematic/types/get_onboarding_state_resp.py new file mode 100644 index 0000000..47d3b11 --- /dev/null +++ b/src/schematic/types/get_onboarding_state_resp.py @@ -0,0 +1,29 @@ +# 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 .onboarding_milestone_view import OnboardingMilestoneView +from .onboarding_path import OnboardingPath +from .onboarding_requirement import OnboardingRequirement +from .onboarding_requirement_view import OnboardingRequirementView +from .onboarding_track import OnboardingTrack + + +class GetOnboardingStateResp(UniversalBaseModel): + environment_id: typing.Optional[str] = None + milestones: typing.List[OnboardingMilestoneView] + path: typing.Optional[OnboardingPath] = None + requirements: typing.List[OnboardingRequirementView] + suggested_next: typing.List[OnboardingRequirement] + track: typing.Optional[OnboardingTrack] = 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/schematic/types/integration_config.py b/src/schematic/types/integration_config.py index d598f9e..9efe950 100644 --- a/src/schematic/types/integration_config.py +++ b/src/schematic/types/integration_config.py @@ -60,6 +60,7 @@ class IntegrationConfig_Stripe(UniversalBaseModel): is_sandbox: bool live_mode: bool onboard_url: typing.Optional[str] = None + return_to: typing.Optional[str] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/schematic/types/manage_plan_request.py b/src/schematic/types/manage_plan_request.py index 14f7661..c9fb367 100644 --- a/src/schematic/types/manage_plan_request.py +++ b/src/schematic/types/manage_plan_request.py @@ -5,6 +5,7 @@ import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .billing_collection_method import BillingCollectionMethod from .checkout_field_value import CheckoutFieldValue from .plan_selection import PlanSelection from .update_credit_bundle_request_body import UpdateCreditBundleRequestBody @@ -12,10 +13,25 @@ class ManagePlanRequest(UniversalBaseModel): + activate_on_payment: typing.Optional[bool] = pydantic.Field(default=None) + """ + If true, the company gets the plan only once the first invoice is paid. Only applies to an invoiced subscription. Defaults to false. + """ + add_on_selections: typing.List[PlanSelection] base_plan_id: typing.Optional[str] = None base_plan_price_id: typing.Optional[str] = None base_plan_version_id: typing.Optional[str] = None + billing_cycle_anchor: typing.Optional[dt.datetime] = pydantic.Field(default=None) + """ + The date the subscription's billing period renews on. Only honored when starting a new subscription; changing the anchor on an existing subscription is not supported. + """ + + billing_email: typing.Optional[str] = pydantic.Field(default=None) + """ + Address the invoice is sent to. Required when collection_method is send_invoice. + """ + billing_entity_id: typing.Optional[str] = pydantic.Field(default=None) """ The company that pays for this subscription. Must already have a Stripe customer. Only honored when starting a new subscription. @@ -26,10 +42,20 @@ class ManagePlanRequest(UniversalBaseModel): If false, subscription cancels at period end. Only applies when removing all plans. Defaults to true. """ + collection_method: typing.Optional[BillingCollectionMethod] = pydantic.Field(default=None) + """ + How the subscription is paid: charged to a payment method on file, or invoiced with payment terms. Invoicing is only available when starting a new subscription. Defaults to charge_automatically. + """ + company_id: str coupon_external_id: typing.Optional[str] = None credit_bundles: typing.List[UpdateCreditBundleRequestBody] custom_field_values: typing.List[CheckoutFieldValue] + days_until_due: typing.Optional[int] = pydantic.Field(default=None) + """ + Payment terms in days for an invoiced subscription. Defaults to 30. + """ + pay_in_advance_entitlements: typing.List[UpdatePayInAdvanceRequestBody] payment_method_external_id: typing.Optional[str] = None promo_code: typing.Optional[str] = None @@ -38,6 +64,16 @@ class ManagePlanRequest(UniversalBaseModel): If true and cancel_immediately is true, issue prorated credit. Only applies when removing all plans. Defaults to true. """ + prorate_first_period: typing.Optional[bool] = pydantic.Field(default=None) + """ + When true, the partial period between the subscription starting and its renewal date is billed pro rata straight away. When false that period is free and no invoice is raised until the renewal date. Only applies alongside billing_cycle_anchor. Defaults to true. + """ + + send_invoice: typing.Optional[bool] = pydantic.Field(default=None) + """ + Whether Stripe emails the invoice when it is finalized. Only applies to an invoiced subscription. Defaults to true. + """ + trial_end: typing.Optional[dt.datetime] = None if IS_PYDANTIC_V2: diff --git a/src/schematic/types/migration_proration_behavior.py b/src/schematic/types/migration_proration_behavior.py new file mode 100644 index 0000000..8357c61 --- /dev/null +++ b/src/schematic/types/migration_proration_behavior.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +MigrationProrationBehavior = typing.Union[typing.Literal["always_invoice", "create_prorations", "none"], typing.Any] diff --git a/src/schematic/types/onboarding_milestone.py b/src/schematic/types/onboarding_milestone.py new file mode 100644 index 0000000..4f817bb --- /dev/null +++ b/src/schematic/types/onboarding_milestone.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +OnboardingMilestone = typing.Union[typing.Literal["evaluated", "implemented"], typing.Any] diff --git a/src/schematic/types/onboarding_milestone_view.py b/src/schematic/types/onboarding_milestone_view.py new file mode 100644 index 0000000..f9ea47b --- /dev/null +++ b/src/schematic/types/onboarding_milestone_view.py @@ -0,0 +1,25 @@ +# 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 +from .onboarding_milestone import OnboardingMilestone +from .onboarding_requirement import OnboardingRequirement + + +class OnboardingMilestoneView(UniversalBaseModel): + id: OnboardingMilestone + missing: typing.List[OnboardingRequirement] + progress: float + reached_at: typing.Optional[dt.datetime] = 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/schematic/types/onboarding_path.py b/src/schematic/types/onboarding_path.py new file mode 100644 index 0000000..bacb372 --- /dev/null +++ b/src/schematic/types/onboarding_path.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +OnboardingPath = typing.Union[typing.Literal["agent", "app"], typing.Any] diff --git a/src/schematic/types/onboarding_requirement.py b/src/schematic/types/onboarding_requirement.py new file mode 100644 index 0000000..cd0ed65 --- /dev/null +++ b/src/schematic/types/onboarding_requirement.py @@ -0,0 +1,10 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +OnboardingRequirement = typing.Union[ + typing.Literal[ + "connect_billing", "create_api_key", "first_flag_check", "import_companies", "model_packaging", "send_events" + ], + typing.Any, +] diff --git a/src/schematic/types/onboarding_requirement_status.py b/src/schematic/types/onboarding_requirement_status.py new file mode 100644 index 0000000..fbcec58 --- /dev/null +++ b/src/schematic/types/onboarding_requirement_status.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +OnboardingRequirementStatus = typing.Union[typing.Literal["available", "blocked", "complete"], typing.Any] diff --git a/src/schematic/types/onboarding_requirement_view.py b/src/schematic/types/onboarding_requirement_view.py new file mode 100644 index 0000000..a2675d2 --- /dev/null +++ b/src/schematic/types/onboarding_requirement_view.py @@ -0,0 +1,26 @@ +# 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 +from .onboarding_requirement import OnboardingRequirement +from .onboarding_requirement_status import OnboardingRequirementStatus + + +class OnboardingRequirementView(UniversalBaseModel): + blocked_by: typing.Optional[typing.List[OnboardingRequirement]] = None + id: OnboardingRequirement + reached_at: typing.Optional[dt.datetime] = None + satisfied_by: typing.Optional[str] = None + status: OnboardingRequirementStatus + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/schematic/types/onboarding_track.py b/src/schematic/types/onboarding_track.py new file mode 100644 index 0000000..13a344a --- /dev/null +++ b/src/schematic/types/onboarding_track.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +OnboardingTrack = typing.Union[typing.Literal["catalog", "single_plan"], typing.Any] diff --git a/src/schematic/types/plan_billing_source.py b/src/schematic/types/plan_billing_source.py new file mode 100644 index 0000000..825fd26 --- /dev/null +++ b/src/schematic/types/plan_billing_source.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +PlanBillingSource = typing.Union[typing.Literal["custom_plan", "manage_plan"], typing.Any] diff --git a/src/schematic/types/plan_bundle_response_data.py b/src/schematic/types/plan_bundle_response_data.py index 550453e..9f0a6df 100644 --- a/src/schematic/types/plan_bundle_response_data.py +++ b/src/schematic/types/plan_bundle_response_data.py @@ -8,6 +8,7 @@ from .billing_product_plan_response_data import BillingProductPlanResponseData from .plan_entitlement_response_data import PlanEntitlementResponseData from .plan_response_data import PlanResponseData +from .plan_version_response_data import PlanVersionResponseData class PlanBundleResponseData(UniversalBaseModel): @@ -15,6 +16,7 @@ class PlanBundleResponseData(UniversalBaseModel): credit_grants: typing.Optional[typing.List[BillingPlanCreditGrantResponseData]] = None entitlements: typing.Optional[typing.List[PlanEntitlementResponseData]] = None plan: typing.Optional[PlanResponseData] = None + plan_version: typing.Optional[PlanVersionResponseData] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/schematic/types/plan_change_response_data.py b/src/schematic/types/plan_change_response_data.py index 1c3a9df..1ba34d7 100644 --- a/src/schematic/types/plan_change_response_data.py +++ b/src/schematic/types/plan_change_response_data.py @@ -16,6 +16,7 @@ from .plan_snapshot_view import PlanSnapshotView from .plan_version_snapshot_view import PlanVersionSnapshotView from .subscription_trait_update import SubscriptionTraitUpdate +from .trial_status import TrialStatus class PlanChangeResponseData(UniversalBaseModel): @@ -68,6 +69,21 @@ class PlanChangeResponseData(UniversalBaseModel): Any traits were updated as part of this plan change (via pay-in-advance entitlements). """ + trial_converted_at: typing.Optional[dt.datetime] = pydantic.Field(default=None) + """ + When the company's trial had converted to a paid subscription as of this change. Null when the trial had not converted, or for changes recorded before trial status was tracked. + """ + + trial_expires_at: typing.Optional[dt.datetime] = pydantic.Field(default=None) + """ + When the company's trial was set to end as of this change. Null when the company had never trialed, or for changes recorded before trial status was tracked. + """ + + trial_status: typing.Optional[TrialStatus] = pydantic.Field(default=None) + """ + The company's trial status. Null when the company had never trialed, or for changes recorded before trial status was tracked. + """ + updated_at: dt.datetime user_id: typing.Optional[str] = None user_name: typing.Optional[str] = None diff --git a/src/schematic/types/plan_credit_grant_view.py b/src/schematic/types/plan_credit_grant_view.py index 3514c39..fec3c3d 100644 --- a/src/schematic/types/plan_credit_grant_view.py +++ b/src/schematic/types/plan_credit_grant_view.py @@ -28,6 +28,7 @@ class PlanCreditGrantView(UniversalBaseModel): billing_credit_auto_topup_threshold_credits: typing.Optional[int] = None billing_credit_auto_topup_threshold_percent: typing.Optional[int] = None billing_credit_can_buy_bundles: bool + company_credit_amount: int created_at: dt.datetime credit: typing.Optional[BillingCreditView] = None credit_amount: int diff --git a/src/schematic/types/plan_version_migration_preview_company_response_data.py b/src/schematic/types/plan_version_migration_preview_company_response_data.py index 17c6051..661f9b2 100644 --- a/src/schematic/types/plan_version_migration_preview_company_response_data.py +++ b/src/schematic/types/plan_version_migration_preview_company_response_data.py @@ -13,6 +13,7 @@ class PlanVersionMigrationPreviewCompanyResponseData(UniversalBaseModel): note: typing.Optional[str] = None plan_version_id_from: typing.Optional[str] = None will_update_subscription: bool + would_fail: bool if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/schematic/types/plan_version_migration_preview_response_data.py b/src/schematic/types/plan_version_migration_preview_response_data.py index 3000d3e..c055805 100644 --- a/src/schematic/types/plan_version_migration_preview_response_data.py +++ b/src/schematic/types/plan_version_migration_preview_response_data.py @@ -9,6 +9,7 @@ class PlanVersionMigrationPreviewResponseData(UniversalBaseModel): companies: typing.List[PlanVersionMigrationPreviewCompanyResponseData] + has_billing_changes: bool if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/schematic/types/plan_version_migration_response_data.py b/src/schematic/types/plan_version_migration_response_data.py index e3bfbc6..31a404d 100644 --- a/src/schematic/types/plan_version_migration_response_data.py +++ b/src/schematic/types/plan_version_migration_response_data.py @@ -5,6 +5,7 @@ import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .migration_proration_behavior import MigrationProrationBehavior from .plan_version_migration_status import PlanVersionMigrationStatus from .plan_version_migration_strategy import PlanVersionMigrationStrategy @@ -20,6 +21,7 @@ class PlanVersionMigrationResponseData(UniversalBaseModel): plan_version_id_from: typing.Optional[str] = None plan_version_id_to: str plan_version_ids_from: typing.List[str] + proration_behavior: typing.Optional[MigrationProrationBehavior] = None skipped_companies: int started_at: typing.Optional[dt.datetime] = None status: PlanVersionMigrationStatus diff --git a/src/schematic/types/preflight_event_usage_request_body.py b/src/schematic/types/preflight_event_usage_request_body.py new file mode 100644 index 0000000..7de0041 --- /dev/null +++ b/src/schematic/types/preflight_event_usage_request_body.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 PreflightEventUsageRequestBody(UniversalBaseModel): + event_subtype: str = pydantic.Field() + """ + The event subtype the usage would be recorded under + """ + + quantity: int = pydantic.Field() + """ + How many units of the event subtype the action would record. Zero has no effect + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/schematic/types/preflight_request_body.py b/src/schematic/types/preflight_request_body.py new file mode 100644 index 0000000..bff0e4f --- /dev/null +++ b/src/schematic/types/preflight_request_body.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 .preflight_event_usage_request_body import PreflightEventUsageRequestBody + + +class PreflightRequestBody(UniversalBaseModel): + credit_cost: typing.Optional[typing.Dict[str, float]] = pydantic.Field(default=None) + """ + Cost in credits of the action, keyed by credit ID, for callers that have already computed it. Takes precedence over usage and event_usage on credit balance conditions for the same credit. A cost of zero means the action is free, not that the input is absent + """ + + event_usage: typing.Optional[PreflightEventUsageRequestBody] = pydantic.Field(default=None) + """ + Usage of a specific event subtype. Preferred over usage when the subtype is known, since it only affects conditions measuring that subtype + """ + + usage: typing.Optional[int] = pydantic.Field(default=None) + """ + Quantity of usage to simulate against any numeric condition encountered while evaluating the flag. Zero has no effect + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/schematic/types/preview_subscription_finance_response_data.py b/src/schematic/types/preview_subscription_finance_response_data.py index ceaa47d..176557d 100644 --- a/src/schematic/types/preview_subscription_finance_response_data.py +++ b/src/schematic/types/preview_subscription_finance_response_data.py @@ -11,6 +11,7 @@ class PreviewSubscriptionFinanceResponseData(UniversalBaseModel): amount_off: int + discount_amount: int discounts: typing.List[PreviewSubscriptionDiscountResponseData] due_now: int new_charges: int @@ -19,6 +20,7 @@ class PreviewSubscriptionFinanceResponseData(UniversalBaseModel): period_start: dt.datetime promo_code_applied: bool proration: int + proration_billed_at: typing.Optional[dt.datetime] = None tax_amount: typing.Optional[int] = None tax_display_name: typing.Optional[str] = None tax_require_billing_details: bool diff --git a/src/schematic/types/rules_engine_schema_version.py b/src/schematic/types/rules_engine_schema_version.py index 69b0d3e..7db8d71 100644 --- a/src/schematic/types/rules_engine_schema_version.py +++ b/src/schematic/types/rules_engine_schema_version.py @@ -2,4 +2,4 @@ import typing -RulesEngineSchemaVersion = typing.Union[typing.Literal["v5b3e7220", "placeholder-for-fern-compatibility"], typing.Any] +RulesEngineSchemaVersion = typing.Union[typing.Literal["vc8eb8df4", "placeholder-for-fern-compatibility"], typing.Any] diff --git a/src/schematic/types/stripe_integration_config.py b/src/schematic/types/stripe_integration_config.py index 84c885e..2c19740 100644 --- a/src/schematic/types/stripe_integration_config.py +++ b/src/schematic/types/stripe_integration_config.py @@ -37,6 +37,11 @@ class StripeIntegrationConfig(UniversalBaseModel): Onboarding URL returned during the v2 (Connect) install flow before activation """ + return_to: typing.Optional[str] = pydantic.Field(default=None) + """ + App location that started the connect flow; the OAuth callback redirects back there on success + """ + if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 else: diff --git a/src/schematic/types/upcoming_invoice_response_data.py b/src/schematic/types/upcoming_invoice_response_data.py new file mode 100644 index 0000000..74a7d08 --- /dev/null +++ b/src/schematic/types/upcoming_invoice_response_data.py @@ -0,0 +1,41 @@ +# 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 +from .billing_provider_type import BillingProviderType +from .invoice_status import InvoiceStatus + + +class UpcomingInvoiceResponseData(UniversalBaseModel): + amount_due: int + amount_paid: int + amount_remaining: int + collection_method: str + company_id: typing.Optional[str] = None + created_at: dt.datetime + currency: str + customer_external_id: str + due_date: typing.Optional[dt.datetime] = None + ending_balance: int + environment_id: str + external_id: typing.Optional[str] = None + payment_method_external_id: typing.Optional[str] = None + provider_type: BillingProviderType + starting_balance: int + status: typing.Optional[InvoiceStatus] = None + subscription_external_id: typing.Optional[str] = None + subtotal: int + updated_at: dt.datetime + url: 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/schematic/types/update_billing_plan_credit_grant_request_body.py b/src/schematic/types/update_billing_plan_credit_grant_request_body.py index 0c6d2c2..1e8854e 100644 --- a/src/schematic/types/update_billing_plan_credit_grant_request_body.py +++ b/src/schematic/types/update_billing_plan_credit_grant_request_body.py @@ -26,14 +26,23 @@ class UpdateBillingPlanCreditGrantRequestBody(UniversalBaseModel): auto_topup_self_service: typing.Optional[bool] = None auto_topup_threshold_credits: typing.Optional[int] = None auto_topup_threshold_percent: typing.Optional[int] = None - can_buy_bundles: typing.Optional[bool] = None + can_buy_bundles: typing.Optional[bool] = pydantic.Field(default=None) + """ + Deprecated: use compatible_plan_ids on credit bundles instead. Still accepted; writes through to the credit's bundle compatibility. + """ + + company_credit_amount: typing.Optional[int] = pydantic.Field(default=None) + """ + Credits granted once per company on top of the per-license amount. Only valid when the grant scales per license. + """ + credit_amount: typing.Optional[int] = None expiry_type: typing.Optional[BillingCreditExpiryType] = None expiry_unit: typing.Optional[BillingCreditExpiryUnit] = None expiry_unit_count: typing.Optional[int] = None license_id: typing.Optional[str] = pydantic.Field(default=None) """ - The license whose quantity scales this grant. Cannot be changed after creation. + The license whose quantity scales this grant. Cleared when the grant moves off per-license scaling. """ reset_cadence: BillingPlanCreditGrantResetCadence @@ -46,7 +55,7 @@ class UpdateBillingPlanCreditGrantRequestBody(UniversalBaseModel): scaling: typing.Optional[PlanCreditGrantScaling] = pydantic.Field(default=None) """ - Whether the grant is a fixed amount per company, or issued once per license the company holds. Cannot be changed after creation. + Whether the grant is a fixed amount per company, or issued once per license the company holds. Changing this re-issues the credits companies already hold for this grant. """ if IS_PYDANTIC_V2: diff --git a/src/schematic/types/upsert_company_request_body.py b/src/schematic/types/upsert_company_request_body.py index ba8ada6..06def17 100644 --- a/src/schematic/types/upsert_company_request_body.py +++ b/src/schematic/types/upsert_company_request_body.py @@ -31,6 +31,11 @@ class UpsertCompanyRequestBody(UniversalBaseModel): last_seen_at: typing.Optional[dt.datetime] = None name: typing.Optional[str] = None prevent_key_remap: typing.Optional[bool] = None + remove_keys: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + Names of keys to remove from the company. Removing a key the company does not have does nothing, and a company must keep at least one key. + """ + traits: typing.Optional[typing.Dict[str, typing.Any]] = pydantic.Field(default=None) """ A map of trait names to trait values diff --git a/src/schematic/types/upsert_trait_request_body.py b/src/schematic/types/upsert_trait_request_body.py index 154ba17..2c8839e 100644 --- a/src/schematic/types/upsert_trait_request_body.py +++ b/src/schematic/types/upsert_trait_request_body.py @@ -24,6 +24,10 @@ class UpsertTraitRequestBody(UniversalBaseModel): FieldMetadata(alias="set"), pydantic.Field(alias="set", description="Value to set the trait to"), ] = None + """ + Value to set the trait to + """ + trait: str = pydantic.Field() """ Name of the trait to update diff --git a/src/schematic/types/upsert_user_request_body.py b/src/schematic/types/upsert_user_request_body.py index 7c13a84..edf780f 100644 --- a/src/schematic/types/upsert_user_request_body.py +++ b/src/schematic/types/upsert_user_request_body.py @@ -40,6 +40,11 @@ class UpsertUserRequestBody(UniversalBaseModel): last_seen_at: typing.Optional[dt.datetime] = None name: typing.Optional[str] = None + remove_keys: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + Names of keys to remove from the user. Removing a key the user does not have does nothing, and a user must keep at least one key. + """ + traits: typing.Optional[typing.Dict[str, typing.Any]] = pydantic.Field(default=None) """ A map of trait names to trait values diff --git a/src/schematic/types/upsert_user_sub_request_body.py b/src/schematic/types/upsert_user_sub_request_body.py index c17913a..11d61ca 100644 --- a/src/schematic/types/upsert_user_sub_request_body.py +++ b/src/schematic/types/upsert_user_sub_request_body.py @@ -30,6 +30,11 @@ class UpsertUserSubRequestBody(UniversalBaseModel): last_seen_at: typing.Optional[dt.datetime] = None name: typing.Optional[str] = None + remove_keys: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + Names of keys to remove from the user. Removing a key the user does not have does nothing, and a user must keep at least one key. + """ + traits: typing.Optional[typing.Dict[str, typing.Any]] = pydantic.Field(default=None) """ A map of trait names to trait values diff --git a/src/schematic/types/who_am_i_response_data.py b/src/schematic/types/who_am_i_response_data.py index 6fc2a83..2a9b095 100644 --- a/src/schematic/types/who_am_i_response_data.py +++ b/src/schematic/types/who_am_i_response_data.py @@ -15,6 +15,7 @@ class WhoAmIResponseData(UniversalBaseModel): api_key_id: typing.Optional[str] = None environment_id: typing.Optional[str] = None environments: typing.List[EnvironmentResponseData] + onboarding_complete: bool stripe_user_id: typing.Optional[str] = None user_id: typing.Optional[str] = None user_name: typing.Optional[str] = None diff --git a/tests/utils/test_http_client.py b/tests/utils/test_http_client.py index ed31173..cfa6acb 100644 --- a/tests/utils/test_http_client.py +++ b/tests/utils/test_http_client.py @@ -1,6 +1,6 @@ # This file was auto-generated by Fern from our API Definition. -from typing import Any, Dict +from typing import Any, Dict, Tuple, cast from unittest.mock import AsyncMock, MagicMock, patch import httpx @@ -11,6 +11,7 @@ HttpClient, _build_url, _should_retry, + drop_content_type_without_body, get_request_body, remove_none_from_dict, ) @@ -121,6 +122,67 @@ def test_explicit_empty_json_body_is_preserved() -> None: assert data_body2 == {} +def test_omitted_body_sends_no_content() -> None: + """A body left at the sentinel was never passed, so nothing is sent. + + This is how an endpoint whose body may be omitted stays bodyless, as opposed to + sending an empty ``{}``. An explicit ``None`` still reaches the wire as ``null``. + """ + omit = cast(Any, ...) + unrelated_request_options: RequestOptions = {"max_retries": 3} + + json_body, data_body = get_request_body(json=omit, data=None, request_options=unrelated_request_options, omit=omit) + assert json_body is None + assert data_body is None + + json_body2, data_body2 = get_request_body( + json=None, data=omit, request_options=unrelated_request_options, omit=omit + ) + assert json_body2 is None + assert data_body2 is None + + # an explicitly passed body is untouched + json_body3, _ = get_request_body(json={"hello": "world"}, data=None, request_options=None, omit=omit) + assert json_body3 == {"hello": "world"} + + +def test_optional_body_sends_no_content_when_every_property_is_omitted() -> None: + """An endpoint that inlines an omittable body sends nothing once every property is omitted. + + The body reaches the client as a dict of sentinels rather than as a single argument, so + ``optional_body`` is what tells the client that an empty result means "no body at all". + """ + omit = cast(Any, ...) + + json_body, data_body = get_request_body( + json={"amount": omit, "source": omit}, data=None, request_options=None, omit=omit, optional_body=True + ) + assert json_body is None + assert data_body is None + + # a body the API requires still goes out as `{}` + required_json_body, _ = get_request_body( + json={"amount": omit, "source": omit}, data=None, request_options=None, omit=omit + ) + assert required_json_body == {} + + # a property the caller did pass keeps the body + populated_json_body, _ = get_request_body( + json={"amount": 1, "source": omit}, data=None, request_options=None, omit=omit, optional_body=True + ) + assert populated_json_body == {"amount": 1} + + # additional body parameters keep the body, since the caller asked for them + with_additional_body_parameters, _ = get_request_body( + json={"amount": omit}, + data=None, + request_options={"additional_body_parameters": {"custom": "value"}}, + omit=omit, + optional_body=True, + ) + assert with_additional_body_parameters == {"custom": "value"} + + 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( @@ -692,3 +754,100 @@ def test_should_not_retry_non_retryable_status_codes(status_code: int) -> None: def test_should_retry_599_upper_boundary() -> None: """Legacy mode retries on >= 500, which includes 599.""" assert _should_retry(_make_response(599)) is True + + +# --------------------------------------------------------------------------- +# RequestOptions timeout resolution tests (timeout / deprecated timeout_in_seconds) +# --------------------------------------------------------------------------- + + +def _sync_client_with_base_timeout(base_timeout: Any) -> Tuple[HttpClient, _DummySyncClient]: + dummy_client = _DummySyncClient() + http_client = HttpClient( + httpx_client=dummy_client, # type: ignore[arg-type] + base_timeout=lambda: base_timeout, + base_headers=lambda: {}, + base_url=lambda: "https://example.com", + ) + return http_client, dummy_client + + +def test_sync_request_options_timeout_used() -> None: + """The new `timeout` request option is passed through to httpx (in seconds).""" + http_client, dummy_client = _sync_client_with_base_timeout(60) + http_client.request(path="/test", method="GET", request_options={"timeout": 30}) + assert dummy_client.last_request_kwargs["timeout"] == 30 + + +def test_sync_request_options_timeout_in_seconds_still_works() -> None: + """The deprecated `timeout_in_seconds` request option remains backwards compatible.""" + http_client, dummy_client = _sync_client_with_base_timeout(60) + http_client.request(path="/test", method="GET", request_options={"timeout_in_seconds": 45}) + assert dummy_client.last_request_kwargs["timeout"] == 45 + + +def test_sync_request_options_timeout_takes_precedence() -> None: + """When both are set, `timeout` wins over `timeout_in_seconds` (same seconds unit).""" + http_client, dummy_client = _sync_client_with_base_timeout(60) + http_client.request(path="/test", method="GET", request_options={"timeout": 30, "timeout_in_seconds": 45}) + assert dummy_client.last_request_kwargs["timeout"] == 30 + + +def test_sync_request_options_timeout_falls_back_to_base() -> None: + """When neither key is set, the client-level base timeout is used.""" + http_client, dummy_client = _sync_client_with_base_timeout(60) + http_client.request(path="/test", method="GET", request_options=None) + assert dummy_client.last_request_kwargs["timeout"] == 60 + + +def test_sync_request_options_timeout_none_falls_back_to_deprecated() -> None: + """An explicit `timeout=None` (dynamic caller) falls back to the deprecated `timeout_in_seconds`.""" + http_client, dummy_client = _sync_client_with_base_timeout(60) + request_options = cast(RequestOptions, {"timeout": None, "timeout_in_seconds": 45}) + http_client.request(path="/test", method="GET", request_options=request_options) + assert dummy_client.last_request_kwargs["timeout"] == 45 + + +@pytest.mark.asyncio +async def test_async_request_options_timeout_takes_precedence() -> None: + """Async: `timeout` wins over the deprecated `timeout_in_seconds`.""" + dummy_client = _DummyAsyncClient() + http_client = AsyncHttpClient( + httpx_client=dummy_client, # type: ignore[arg-type] + base_timeout=lambda: 60, + base_headers=lambda: {}, + base_url=lambda: "https://example.com", + async_base_headers=None, + ) + await http_client.request(path="/test", method="GET", request_options={"timeout": 30, "timeout_in_seconds": 45}) + assert dummy_client.last_request_kwargs["timeout"] == 30 + + +def test_drop_content_type_without_body_omits_header_for_bodyless_optional_call() -> None: + """An optional-body endpoint the caller left empty must not advertise a media type. + + `get_request_body` drops the body, but the endpoint still hands over the content type it + would have used, so a server that branches on the header would see a JSON request carrying + nothing at all. + """ + headers = {"content-type": "application/json", "authorization": "Bearer x"} + + assert drop_content_type_without_body(headers, json_body=None, data_body=None, optional_body=True) == { + "authorization": "Bearer x" + } + + +def test_drop_content_type_without_body_keeps_header_when_a_body_is_sent() -> None: + headers = {"content-type": "application/json"} + + assert ( + drop_content_type_without_body(headers, json_body={"amount": 60}, data_body=None, optional_body=True) == headers + ) + assert drop_content_type_without_body(headers, json_body=None, data_body="raw", optional_body=True) == headers + + +def test_drop_content_type_without_body_leaves_required_body_endpoints_alone() -> None: + """Without the opt-in, an endpoint keeps the header it has always sent.""" + headers = {"Content-Type": "application/json"} + + assert drop_content_type_without_body(headers, json_body=None, data_body=None, optional_body=False) == headers