diff --git a/poetry.lock b/poetry.lock
index cea859e8..dfe67d2f 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -38,13 +38,13 @@ trio = ["trio (>=0.26.1)"]
[[package]]
name = "certifi"
-version = "2025.6.15"
+version = "2025.8.3"
description = "Python package for providing Mozilla's CA Bundle."
optional = false
python-versions = ">=3.7"
files = [
- {file = "certifi-2025.6.15-py3-none-any.whl", hash = "sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057"},
- {file = "certifi-2025.6.15.tar.gz", hash = "sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b"},
+ {file = "certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5"},
+ {file = "certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407"},
]
[[package]]
diff --git a/pyproject.toml b/pyproject.toml
index 0f52cf33..c9f17861 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -3,7 +3,7 @@ name = "sayari"
[tool.poetry]
name = "sayari"
-version = "0.1.42"
+version = "0.1.43"
description = "A Python SDK for Sayari"
readme = "README.md"
authors = [
diff --git a/reference.md b/reference.md
index 77bfc4a7..a76be864 100644
--- a/reference.md
+++ b/reference.md
@@ -2643,6 +2643,463 @@ client.ontology.get_source_types(
+
+
+
+
+## ProjectEntityAttributes
+client.project_entity_attributes.update_project_entity_attribute(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Updates a specific attribute for a project entity.
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from sayari import Sayari
+from sayari.project_entity_attributes import UpdateProjectEntityAttributeRequest
+
+client = Sayari(
+ client_id="YOUR_CLIENT_ID",
+ client_secret="YOUR_CLIENT_SECRET",
+)
+client.project_entity_attributes.update_project_entity_attribute(
+ project_id="V03eYM",
+ project_entity_id="BG72YW",
+ attribute_id="xG8wYP",
+ request=UpdateProjectEntityAttributeRequest(
+ field="name",
+ value="updated name",
+ match_resolution=True,
+ ),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**project_id:** `str`
+
+
+
+
+
+-
+
+**project_entity_id:** `str`
+
+
+
+
+
+-
+
+**attribute_id:** `str`
+
+
+
+
+
+-
+
+**request:** `UpdateProjectEntityAttributeRequest`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+## ProjectEntitySupplyChainSnapshots
+client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_snapshots(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Retrieves all supply chain snapshots for a project entity.
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from sayari import Sayari
+
+client = Sayari(
+ client_id="YOUR_CLIENT_ID",
+ client_secret="YOUR_CLIENT_SECRET",
+)
+client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_snapshots(
+ project_id="V03eYM",
+ project_entity_id="BG72YW",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**project_id:** `str`
+
+
+
+
+
+-
+
+**project_entity_id:** `str`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_snapshot_by_id(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Retrieves a specific supply chain snapshot by ID for a project entity.
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from sayari import Sayari
+
+client = Sayari(
+ client_id="YOUR_CLIENT_ID",
+ client_secret="YOUR_CLIENT_SECRET",
+)
+client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_snapshot_by_id(
+ project_id="V03eYM",
+ project_entity_id="BG72YW",
+ snapshot_id="sN4p2K",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**project_id:** `str`
+
+
+
+
+
+-
+
+**project_entity_id:** `str`
+
+
+
+
+
+-
+
+**snapshot_id:** `str`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.project_entity_supply_chain_snapshots.create_project_entity_supply_chain_snapshot(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Creates a new supply chain snapshot for a project entity.
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from sayari import Sayari
+from sayari.project_entity_supply_chain_snapshots import (
+ CreateProjectEntitySupplyChainSnapshotRequest,
+)
+
+client = Sayari(
+ client_id="YOUR_CLIENT_ID",
+ client_secret="YOUR_CLIENT_SECRET",
+)
+client.project_entity_supply_chain_snapshots.create_project_entity_supply_chain_snapshot(
+ project_id="V03eYM",
+ project_entity_id="BG72YW",
+ request=CreateProjectEntitySupplyChainSnapshotRequest(
+ label="Q1 2024 Supply Chain Analysis",
+ ),
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**project_id:** `str`
+
+
+
+
+
+-
+
+**project_entity_id:** `str`
+
+
+
+
+
+-
+
+**request:** `CreateProjectEntitySupplyChainSnapshotRequest`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.project_entity_supply_chain_snapshots.delete_project_entity_supply_chain_snapshot_by_id(...)
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Deletes a specific supply chain snapshot by ID for a project entity.
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from sayari import Sayari
+
+client = Sayari(
+ client_id="YOUR_CLIENT_ID",
+ client_secret="YOUR_CLIENT_SECRET",
+)
+client.project_entity_supply_chain_snapshots.delete_project_entity_supply_chain_snapshot_by_id(
+ project_id="project_id",
+ project_entity_id="project_entity_id",
+ snapshot_id="snapshot_id",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**project_id:** `str`
+
+
+
+
+
+-
+
+**project_entity_id:** `str`
+
+
+
+
+
+-
+
+**snapshot_id:** `str`
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
@@ -2683,13 +3140,13 @@ client = Sayari(
client_secret="YOUR_CLIENT_SECRET",
)
client.project_entity.create_project_entity(
- project_id="YVB88Y",
+ project_id="0n4473",
request=CreateResolvedProjectEntityRequest(
- name=["VTB Bank"],
- country=["RUS"],
- address=["Moscow"],
- identifier=["253400V1H6ART1UQ0N98"],
- profile="corporate",
+ name=["Marvel Garment"],
+ country=["KHM"],
+ address=[
+ "Beung Thom 3 Village, Sangkat Beung Thom, Posenchey, Phnom Penh"
+ ],
),
)
@@ -2826,7 +3283,7 @@ client.project_entity.get_project_entities(
-
-**match_result:** `typing.Optional[typing.Sequence[MatchResult]]` — Filter by match result
+**match_count:** `typing.Optional[MatchCount]` — Filter by match count
@@ -2834,7 +3291,7 @@ client.project_entity.get_project_entities(
-
-**match_strength_v_1:** `typing.Optional[typing.Sequence[MatchStrengthEnum]]` — Filter by match strength
+**match_strength:** `typing.Optional[typing.Sequence[MatchStrengthEnum]]` — Filter by match strength
@@ -3066,7 +3523,7 @@ client.project_entity.get_project_entity(
-
-**match_result:** `typing.Optional[typing.Sequence[MatchResult]]` — Filter by match result
+**match_count:** `typing.Optional[MatchCount]` — Filter by match count
@@ -3074,7 +3531,7 @@ client.project_entity.get_project_entity(
-
-**match_strength_v_1:** `typing.Optional[typing.Sequence[MatchStrengthEnum]]` — Filter by match strength
+**match_strength:** `typing.Optional[typing.Sequence[MatchStrengthEnum]]` — Filter by match strength
@@ -3530,7 +3987,7 @@ client.project_entity.project_entity_supply_chain(
-
-**risk:** `typing.Optional[typing.Sequence[Risk]]` — Risk leaf node filter. Only return supply chains that end with a supplier that has 1+ of the specified risk factors.
+**product:** `typing.Optional[typing.Sequence[str]]` — Product root edge filter. Filters results to include only trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.
@@ -3538,7 +3995,7 @@ client.project_entity.project_entity_supply_chain(
-
-**not_risk:** `typing.Optional[typing.Sequence[Risk]]` — Risk leaf node filter. Only return supply chains that end with a supplier that has none of the specified risk factors.
+**not_product:** `typing.Optional[typing.Sequence[str]]` — Product root edge filter. Filters results to exclude any trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.
@@ -3546,7 +4003,7 @@ client.project_entity.project_entity_supply_chain(
-
-**countries:** `typing.Optional[typing.Sequence[Country]]` — Country leaf node filter. Only return supply chains that end with a supplier in 1+ of the specified countries.
+**risk:** `typing.Optional[typing.Sequence[Risk]]` — Risk leaf node filter. Only return supply chains that end with a supplier that has 1+ of the specified risk factors.
@@ -3554,7 +4011,7 @@ client.project_entity.project_entity_supply_chain(
-
-**not_countries:** `typing.Optional[typing.Sequence[Country]]` — Country leaf node filter. Only return supply chains that end with a supplier in none of the specified countries.
+**not_risk:** `typing.Optional[typing.Sequence[Risk]]` — Risk leaf node filter. Only return supply chains that end with a supplier that has none of the specified risk factors.
@@ -3562,7 +4019,7 @@ client.project_entity.project_entity_supply_chain(
-
-**shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from any tier matches the provided values.
+**countries:** `typing.Optional[typing.Sequence[Country]]` — Country leaf node filter. Only return supply chains that end with a supplier in 1+ of the specified countries.
@@ -3570,7 +4027,7 @@ client.project_entity.project_entity_supply_chain(
-
-**not_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where none of the shipment countries from any tier matches the provided values.
+**not_countries:** `typing.Optional[typing.Sequence[Country]]` — Country leaf node filter. Only return supply chains that end with a supplier in none of the specified countries.
@@ -3578,7 +4035,7 @@ client.project_entity.project_entity_supply_chain(
-
-**tier_1_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from tier 1 matches the provided values.
+**shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from any tier matches the provided values.
@@ -3586,7 +4043,7 @@ client.project_entity.project_entity_supply_chain(
-
-**tier_2_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from tier 2 matches the provided values.
+**not_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where none of the shipment countries from any tier matches the provided values.
@@ -3594,7 +4051,7 @@ client.project_entity.project_entity_supply_chain(
-
-**tier_3_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from tier 3 matches the provided values.
+**tier_1_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from tier 1 matches the provided values.
@@ -3602,7 +4059,7 @@ client.project_entity.project_entity_supply_chain(
-
-**tier_4_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from tier 4 matches the provided values.
+**tier_2_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from tier 2 matches the provided values.
@@ -3610,7 +4067,7 @@ client.project_entity.project_entity_supply_chain(
-
-**tier_5_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from tier 5 matches the provided values.
+**tier_3_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from tier 3 matches the provided values.
@@ -3618,7 +4075,7 @@ client.project_entity.project_entity_supply_chain(
-
-**product:** `typing.Optional[typing.Sequence[str]]` — Product root edge filter. Only return supply chains that start with an edge that has 1+ of the specified HS codes.
+**tier_4_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from tier 4 matches the provided values.
@@ -3626,7 +4083,7 @@ client.project_entity.project_entity_supply_chain(
-
-**not_product:** `typing.Optional[typing.Sequence[str]]` — Product root edge filter. Only return supply chains that start with an edge that has none of the specified HS codes.
+**tier_5_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from tier 5 matches the provided values.
@@ -3771,7 +4228,7 @@ client.project_entity.project_entity_supply_chain_summary(
-
-**risk_factors:** `typing.Optional[typing.Sequence[Risk]]` — Risk leaf node filter. Only return supply chains that end with a supplier that has 1+ of the specified risk factors.
+**product:** `typing.Optional[typing.Sequence[str]]` — Product root edge filter. Filters results to include only trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.
@@ -3779,7 +4236,7 @@ client.project_entity.project_entity_supply_chain_summary(
-
-**not_risk:** `typing.Optional[typing.Sequence[Risk]]` — Risk leaf node filter. Only return supply chains that end with a supplier that has none of the specified risk factors.
+**not_product:** `typing.Optional[typing.Sequence[str]]` — Product root edge filter. Filters results to exclude any trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.
@@ -3787,7 +4244,7 @@ client.project_entity.project_entity_supply_chain_summary(
-
-**countries:** `typing.Optional[typing.Sequence[Country]]` — Country leaf node filter. Only return supply chains that end with a supplier in 1+ of the specified countries.
+**risk_factors:** `typing.Optional[typing.Sequence[Risk]]` — Risk leaf node filter. Only return supply chains that end with a supplier that has 1+ of the specified risk factors.
@@ -3795,7 +4252,7 @@ client.project_entity.project_entity_supply_chain_summary(
-
-**not_countries:** `typing.Optional[typing.Sequence[Country]]` — Country leaf node filter. Only return supply chains that end with a supplier in none of the specified countries.
+**not_risk:** `typing.Optional[typing.Sequence[Risk]]` — Risk leaf node filter. Only return supply chains that end with a supplier that has none of the specified risk factors.
@@ -3803,7 +4260,7 @@ client.project_entity.project_entity_supply_chain_summary(
-
-**product:** `typing.Optional[typing.Sequence[str]]` — Product root edge filter. Only return supply chains that start with an edge that has 1+ of the specified HS codes.
+**countries:** `typing.Optional[typing.Sequence[Country]]` — Country leaf node filter. Only return supply chains that end with a supplier in 1+ of the specified countries.
@@ -3811,7 +4268,7 @@ client.project_entity.project_entity_supply_chain_summary(
-
-**not_product:** `typing.Optional[typing.Sequence[str]]` — Product root edge filter. Only return supply chains that start with an edge that has none of the specified HS codes.
+**not_countries:** `typing.Optional[typing.Sequence[Country]]` — Country leaf node filter. Only return supply chains that end with a supplier in none of the specified countries.
@@ -3908,7 +4365,7 @@ Create a new project.
```python
from sayari import Sayari
-from sayari.project import CreateProjectRequest
+from sayari.project import CreateProjectRequest, ProjectShareOnCreate
client = Sayari(
client_id="YOUR_CLIENT_ID",
@@ -3916,7 +4373,10 @@ client = Sayari(
)
client.project.create_project(
request=CreateProjectRequest(
- label="Project Alpha",
+ label="My First Project",
+ share=ProjectShareOnCreate(
+ org="admin",
+ ),
),
)
@@ -4046,197 +4506,6 @@ client.project.get_projects(
-
-
-
-
-client.project.get_project_entities(...)
-
--
-
-#### 📝 Description
-
-
--
-
-
--
-
-This endpoint is deprecated. Retrieve a list of entities in a project.
-
-
-
-
-
-#### 🔌 Usage
-
-
--
-
-
--
-
-```python
-from sayari import Sayari
-
-client = Sayari(
- client_id="YOUR_CLIENT_ID",
- client_secret="YOUR_CLIENT_SECRET",
-)
-client.project.get_project_entities(
- id="gPq6EY",
- accept="application/json",
-)
-
-```
-
-
-
-
-
-#### ⚙️ Parameters
-
-
--
-
-
--
-
-**id:** `str` — The project identifier.
-
-
-
-
-
--
-
-**accept:** `GetProjectEntitiesAcceptHeader` — The response format. Defaults to application/json.
-
-
-
-
-
--
-
-**next:** `typing.Optional[str]` — The pagination token for the next page of entities.
-
-
-
-
-
--
-
-**prev:** `typing.Optional[str]` — The pagination token for the previous page of entities.
-
-
-
-
-
--
-
-**limit:** `typing.Optional[int]` — Limit total entities returned. Defaults to 1,000. Max 10,000.
-
-
-
-
-
--
-
-**entity_types:** `typing.Optional[typing.Union[Entities, typing.Sequence[Entities]]]` — Only return entities of the specified [entity type(s)](/sayari-library/ontology/entities). Defaults to all types.
-
-
-
-
-
--
-
-**geo_facets:** `typing.Optional[bool]` — Whether to include geo facets in the response. Defaults to false.
-
-
-
-
-
--
-
-**hs_codes:** `typing.Optional[typing.Union[str, typing.Sequence[str]]]` — Only return entities with the specified HS code(s) in their supply chain.
-
-
-
-
-
--
-
-**received_hs_codes:** `typing.Optional[typing.Union[str, typing.Sequence[str]]]` — Only return entities that received the specified HS code(s).
-
-
-
-
-
--
-
-**shipped_hs_codes:** `typing.Optional[typing.Union[str, typing.Sequence[str]]]` — Only return entities that shipped the specified HS code(s).
-
-
-
-
-
--
-
-**combined_hs_codes:** `typing.Optional[typing.Union[str, typing.Sequence[str]]]` — Only return entities that have shipped or received the specified HS code(s).
-
-
-
-
-
--
-
-**translation:** `typing.Optional[str]` — The language code to translate the entity labels to. Defaults to the user's preferred language.
-
-
-
-
-
--
-
-**sort:** `typing.Optional[SortField]`
-
-
-
-
-
--
-
-**filters:** `typing.Optional[
- typing.Union[ProjectEntitiesFilter, typing.Sequence[ProjectEntitiesFilter]]
-]` — Filter for entities in a project. The format is `field=value`, where the equal sign is encoded as `%3D`. Supported fields are as follows
-
-
-
-
-
--
-
-**aggregations:** `typing.Optional[
- typing.Union[
- ProjectEntitiesAggsDefinition,
- typing.Sequence[ProjectEntitiesAggsDefinition],
- ]
-]` — Aggregations that should be returned for entities in the project.
-
-
-
-
-
--
-
-**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
-
-
-
-
-
-
-
@@ -5738,7 +6007,7 @@ client.supply_chain.upstream_trade_traversal(
-
-**risk:** `typing.Optional[typing.Sequence[Risk]]` — Risk leaf node filter. Only return supply chains that end with a supplier that has 1+ of the specified risk factors.
+**product:** `typing.Optional[typing.Sequence[str]]` — Product root edge filter. Filters results to include only trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.
@@ -5746,7 +6015,7 @@ client.supply_chain.upstream_trade_traversal(
-
-**not_risk:** `typing.Optional[typing.Sequence[Risk]]` — Risk leaf node filter. Only return supply chains that end with a supplier that has none of the specified risk factors.
+**not_product:** `typing.Optional[typing.Sequence[str]]` — Product root edge filter. Filters results to exclude any trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.
@@ -5754,7 +6023,7 @@ client.supply_chain.upstream_trade_traversal(
-
-**countries:** `typing.Optional[typing.Sequence[Country]]` — Country leaf node filter. Only return supply chains that end with a supplier in 1+ of the specified countries.
+**risk:** `typing.Optional[typing.Sequence[Risk]]` — Risk leaf node filter. Only return supply chains that end with a supplier that has 1+ of the specified risk factors.
@@ -5762,7 +6031,7 @@ client.supply_chain.upstream_trade_traversal(
-
-**not_countries:** `typing.Optional[typing.Sequence[Country]]` — Country leaf node filter. Only return supply chains that end with a supplier in none of the specified countries.
+**not_risk:** `typing.Optional[typing.Sequence[Risk]]` — Risk leaf node filter. Only return supply chains that end with a supplier that has none of the specified risk factors.
@@ -5770,7 +6039,7 @@ client.supply_chain.upstream_trade_traversal(
-
-**shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from any tier matches the provided values.
+**countries:** `typing.Optional[typing.Sequence[Country]]` — Country leaf node filter. Only return supply chains that end with a supplier in 1+ of the specified countries.
@@ -5778,7 +6047,7 @@ client.supply_chain.upstream_trade_traversal(
-
-**not_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where none of the shipment countries from any tier matches the provided values.
+**not_countries:** `typing.Optional[typing.Sequence[Country]]` — Country leaf node filter. Only return supply chains that end with a supplier in none of the specified countries.
@@ -5786,7 +6055,7 @@ client.supply_chain.upstream_trade_traversal(
-
-**tier_1_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from tier 1 matches the provided values.
+**shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from any tier matches the provided values.
@@ -5794,7 +6063,7 @@ client.supply_chain.upstream_trade_traversal(
-
-**tier_2_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from tier 2 matches the provided values.
+**not_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where none of the shipment countries from any tier matches the provided values.
@@ -5802,7 +6071,7 @@ client.supply_chain.upstream_trade_traversal(
-
-**tier_3_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from tier 3 matches the provided values.
+**tier_1_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from tier 1 matches the provided values.
@@ -5810,7 +6079,7 @@ client.supply_chain.upstream_trade_traversal(
-
-**tier_4_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from tier 4 matches the provided values.
+**tier_2_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from tier 2 matches the provided values.
@@ -5818,7 +6087,7 @@ client.supply_chain.upstream_trade_traversal(
-
-**tier_5_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from tier 5 matches the provided values.
+**tier_3_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from tier 3 matches the provided values.
@@ -5826,7 +6095,7 @@ client.supply_chain.upstream_trade_traversal(
-
-**product:** `typing.Optional[typing.Sequence[str]]` — Product root edge filter. Only return supply chains that start with an edge that has 1+ of the specified HS codes.
+**tier_4_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from tier 4 matches the provided values.
@@ -5834,7 +6103,7 @@ client.supply_chain.upstream_trade_traversal(
-
-**not_product:** `typing.Optional[typing.Sequence[str]]` — Product root edge filter. Only return supply chains that start with an edge that has none of the specified HS codes.
+**tier_5_shipment_country:** `typing.Optional[typing.Sequence[Country]]` — Filters supply chain paths where 1+ shipment country from tier 5 matches the provided values.
diff --git a/src/sayari/__init__.py b/src/sayari/__init__.py
index c71b0998..95532d56 100644
--- a/src/sayari/__init__.py
+++ b/src/sayari/__init__.py
@@ -13,6 +13,8 @@
ontology,
project,
project_entity,
+ project_entity_attributes,
+ project_entity_supply_chain_snapshots,
record,
resolution,
resource,
@@ -195,9 +197,6 @@
GetProjectEntitiesAcceptHeader,
GetProjectEntitiesResponse,
GetProjectsResponse,
- HsCodeAgg,
- HsCodeAggBucket,
- HsCodeAggTerms,
IntKeyValue,
Project,
ProjectCounts,
@@ -224,14 +223,18 @@
AttributeType,
AttributeTypesResponse,
AttributeValues,
+ AttributesResponse,
BusinessPurpose,
CaseStatus,
CountType,
CreateResolvedProjectEntityRequest,
FacetBucket,
FacetsResponse,
+ GroupedAttribute,
+ GroupedAttributeValue,
Location,
- MatchResult,
+ MatchCount,
+ MatchProfileEnum,
MatchStrengthEnum,
MatchedAttributes,
ProductBucket,
@@ -245,6 +248,7 @@
ProjectEntitySupplyChainSummaryResponse,
ProjectEntitySupplyChainSummaryResponseData,
ProjectEntitySupplyChainUpstream,
+ ProjectRiskCategory,
ProjectRiskFactor,
ResolutionAttributes,
ResolutionProfile,
@@ -263,6 +267,21 @@
UpstreamCount,
UpstreamInfo,
)
+from .project_entity_attributes import (
+ UpdateProjectEntityAttributeRequest,
+ UpdateProjectEntityAttributeResponse,
+ UpdateProjectEntityAttributeResponseData,
+)
+from .project_entity_supply_chain_snapshots import (
+ CreateProjectEntitySupplyChainSnapshotRequest,
+ CreateProjectEntitySupplyChainSnapshotResponse,
+ ProjectEntitySupplyChainSnapshotByIdResponse,
+ ProjectEntitySupplyChainSnapshotData,
+ ProjectEntitySupplyChainSnapshotDetailData,
+ ProjectEntitySupplyChainSnapshotsResponse,
+ SupplyChainEdge,
+ SupplyChainNode,
+)
from .record import GetRecordResponse, RecordReferences
from .resolution import (
MatchExplanation,
@@ -407,6 +426,7 @@
"AttributeTypesResponse",
"AttributeValues",
"Attributes",
+ "AttributesResponse",
"AuthResponse",
"BadGateway",
"BadGatewayResponse",
@@ -443,6 +463,8 @@
"CountryData",
"CountryInfo",
"CountryProperties",
+ "CreateProjectEntitySupplyChainSnapshotRequest",
+ "CreateProjectEntitySupplyChainSnapshotResponse",
"CreateProjectRequest",
"CreateProjectResponse",
"CreateResolvedProjectEntityRequest",
@@ -507,12 +529,11 @@
"GetProjectsResponse",
"GetRecordResponse",
"GetSourceResponse",
+ "GroupedAttribute",
+ "GroupedAttributeValue",
"HistoryInfo",
"HistoryResponse",
"HsCode",
- "HsCodeAgg",
- "HsCodeAggBucket",
- "HsCodeAggTerms",
"HsCodeInfo",
"Identifier",
"IdentifierData",
@@ -525,9 +546,10 @@
"Language",
"ListSourcesResponse",
"Location",
+ "MatchCount",
"MatchExplanation",
+ "MatchProfileEnum",
"MatchQuality",
- "MatchResult",
"MatchStrength",
"MatchStrengthEnum",
"MatchedAttributes",
@@ -610,6 +632,10 @@
"ProjectEntityIdResponse",
"ProjectEntityMatchResponse",
"ProjectEntityResponse",
+ "ProjectEntitySupplyChainSnapshotByIdResponse",
+ "ProjectEntitySupplyChainSnapshotData",
+ "ProjectEntitySupplyChainSnapshotDetailData",
+ "ProjectEntitySupplyChainSnapshotsResponse",
"ProjectEntitySupplyChainSummaryResponse",
"ProjectEntitySupplyChainSummaryResponseData",
"ProjectEntitySupplyChainUpstream",
@@ -617,6 +643,7 @@
"ProjectNotificationData",
"ProjectNotificationRiskData",
"ProjectNotificationsResponse",
+ "ProjectRiskCategory",
"ProjectRiskFactor",
"ProjectShareOnCreate",
"ProjectWithMembers",
@@ -703,6 +730,8 @@
"SupplierMetadata",
"SupplierOrBuyer",
"SupplierSearchResponse",
+ "SupplyChainEdge",
+ "SupplyChainNode",
"Tag",
"TagResponse",
"TierCount",
@@ -733,6 +762,9 @@
"Unit",
"UpdateAttribute",
"UpdateEntityTagsResponse",
+ "UpdateProjectEntityAttributeRequest",
+ "UpdateProjectEntityAttributeResponse",
+ "UpdateProjectEntityAttributeResponseData",
"UpdateProjectEntityTagsBody",
"UpstreamCount",
"UpstreamInfo",
@@ -759,6 +791,8 @@
"ontology",
"project",
"project_entity",
+ "project_entity_attributes",
+ "project_entity_supply_chain_snapshots",
"record",
"resolution",
"resource",
diff --git a/src/sayari/base_client.py b/src/sayari/base_client.py
index eebacc17..f4f0ab9a 100644
--- a/src/sayari/base_client.py
+++ b/src/sayari/base_client.py
@@ -13,6 +13,8 @@
from .negative_news.client import NegativeNewsClient
from .notifications.client import NotificationsClient
from .ontology.client import OntologyClient
+from .project_entity_attributes.client import ProjectEntityAttributesClient
+from .project_entity_supply_chain_snapshots.client import ProjectEntitySupplyChainSnapshotsClient
from .project_entity.client import ProjectEntityClient
from .project.client import ProjectClient
from .record.client import RecordClient
@@ -32,6 +34,8 @@
from .negative_news.client import AsyncNegativeNewsClient
from .notifications.client import AsyncNotificationsClient
from .ontology.client import AsyncOntologyClient
+from .project_entity_attributes.client import AsyncProjectEntityAttributesClient
+from .project_entity_supply_chain_snapshots.client import AsyncProjectEntitySupplyChainSnapshotsClient
from .project_entity.client import AsyncProjectEntityClient
from .project.client import AsyncProjectClient
from .record.client import AsyncRecordClient
@@ -126,6 +130,10 @@ def __init__(
self.negative_news = NegativeNewsClient(client_wrapper=self._client_wrapper)
self.notifications = NotificationsClient(client_wrapper=self._client_wrapper)
self.ontology = OntologyClient(client_wrapper=self._client_wrapper)
+ self.project_entity_attributes = ProjectEntityAttributesClient(client_wrapper=self._client_wrapper)
+ self.project_entity_supply_chain_snapshots = ProjectEntitySupplyChainSnapshotsClient(
+ client_wrapper=self._client_wrapper
+ )
self.project_entity = ProjectEntityClient(client_wrapper=self._client_wrapper)
self.project = ProjectClient(client_wrapper=self._client_wrapper)
self.record = RecordClient(client_wrapper=self._client_wrapper)
@@ -220,6 +228,10 @@ def __init__(
self.negative_news = AsyncNegativeNewsClient(client_wrapper=self._client_wrapper)
self.notifications = AsyncNotificationsClient(client_wrapper=self._client_wrapper)
self.ontology = AsyncOntologyClient(client_wrapper=self._client_wrapper)
+ self.project_entity_attributes = AsyncProjectEntityAttributesClient(client_wrapper=self._client_wrapper)
+ self.project_entity_supply_chain_snapshots = AsyncProjectEntitySupplyChainSnapshotsClient(
+ client_wrapper=self._client_wrapper
+ )
self.project_entity = AsyncProjectEntityClient(client_wrapper=self._client_wrapper)
self.project = AsyncProjectClient(client_wrapper=self._client_wrapper)
self.record = AsyncRecordClient(client_wrapper=self._client_wrapper)
diff --git a/src/sayari/core/client_wrapper.py b/src/sayari/core/client_wrapper.py
index 86784498..f5ae1103 100644
--- a/src/sayari/core/client_wrapper.py
+++ b/src/sayari/core/client_wrapper.py
@@ -22,7 +22,7 @@ def get_headers(self) -> typing.Dict[str, str]:
headers: typing.Dict[str, str] = {
"X-Fern-Language": "Python",
"X-Fern-SDK-Name": "sayari",
- "X-Fern-SDK-Version": "0.1.42",
+ "X-Fern-SDK-Version": "0.1.43",
}
token = self._get_token()
if token is not None:
diff --git a/src/sayari/entity/types/entity_summary_response.py b/src/sayari/entity/types/entity_summary_response.py
index ca79218e..55389baa 100644
--- a/src/sayari/entity/types/entity_summary_response.py
+++ b/src/sayari/entity/types/entity_summary_response.py
@@ -179,6 +179,7 @@ class EntitySummaryResponse(EntityDetails):
"address": 6,
},
reference_id="ecdfb3f2ecc8c3797e77d5795a8066ef/06517802/1540252800000:4a34442eccf1622995130b194a5d50e7",
+ logistics_entity=False,
attributes=AttributeDetails(
name=NameInfo(
offset=0,
@@ -663,6 +664,7 @@ class EntitySummaryResponse(EntityDetails):
"status": 1,
},
reference_id="b9d809b02049993ba8dc2e4c5f7cceca/RM201601838935/1590327027286:74e256656669aa44a5671d4f8898917b",
+ logistics_entity=False,
),
matches={},
),
@@ -744,6 +746,7 @@ class EntitySummaryResponse(EntityDetails):
"address": 4,
},
reference_id="b4d06d4b77f51fab3c77c9653aabdda4/a80e7f4c-c219-437b-9941-32d89ea5885a/1560542045043:15d813b260619393762864f22d3c5b2d",
+ logistics_entity=False,
),
matches={},
),
@@ -821,6 +824,7 @@ class EntitySummaryResponse(EntityDetails):
"address": 1,
},
reference_id="b67ab545f3ddc960d272d11ec5952665/829099316/1591105044949:7d86f50bb976ee542fcfac7bd17b6cca",
+ logistics_entity=False,
),
matches={},
),
@@ -888,6 +892,7 @@ class EntitySummaryResponse(EntityDetails):
"status": 1,
},
reference_id="985b4533cd1cb2db1d736dd31f8e34c9/January 2013.pdf/1643737587282:f1b8f7a9ed23af356dcd37ce6c3ea059",
+ logistics_entity=False,
),
matches={},
),
@@ -937,6 +942,7 @@ class EntitySummaryResponse(EntityDetails):
attribute_counts={"name": 1, "country": 2, "address": 1},
attribute_count={"name": 1, "country": 2, "address": 1},
reference_id="b9d809b02049993ba8dc2e4c5f7cceca/RM201601838933/1590326996292:e8a8042f374e3dc41f62621f66357db2",
+ logistics_entity=False,
),
matches={},
),
@@ -994,6 +1000,7 @@ class EntitySummaryResponse(EntityDetails):
"additional_information": 3,
},
reference_id="b9d809b02049993ba8dc2e4c5f7cceca/RM200901021433/1589580993652:90376816c6039ba02628d4db100fc79f",
+ logistics_entity=False,
),
matches={},
),
@@ -1058,6 +1065,7 @@ class EntitySummaryResponse(EntityDetails):
"status": 1,
},
reference_id="b9d809b02049993ba8dc2e4c5f7cceca/RM201601838934/1590327029874:8bbf00ad8adcb3f371a01e15dea7a1ff",
+ logistics_entity=False,
),
matches={},
),
@@ -1097,6 +1105,7 @@ class EntitySummaryResponse(EntityDetails):
attribute_counts={"name": 1, "country": 1},
attribute_count={"name": 1, "country": 1},
reference_id="542ad2352af9ce07202a2f34d402d5bf/UK00004079756/1723420800000:b2ae9158c53ea711278ce72cccb2c8b2",
+ logistics_entity=False,
),
matches={},
),
diff --git a/src/sayari/entity/types/get_entity_response.py b/src/sayari/entity/types/get_entity_response.py
index 012dbab7..a303ac36 100644
--- a/src/sayari/entity/types/get_entity_response.py
+++ b/src/sayari/entity/types/get_entity_response.py
@@ -171,6 +171,7 @@ class GetEntityResponse(EntityDetails):
"address": 7,
},
reference_id="ecdfb3f2ecc8c3797e77d5795a8066ef/06517802/1540252800000:4a34442eccf1622995130b194a5d50e7",
+ logistics_entity=False,
attributes=AttributeDetails(
additional_information=AdditionalInformationInfo(
limit=1,
@@ -433,6 +434,7 @@ class GetEntityResponse(EntityDetails):
"address": 3,
},
reference_id="ecdfb3f2ecc8c3797e77d5795a8066ef/11043864/1540252800000:40ec7b0310d308ebf9006148b53a2802",
+ logistics_entity=False,
),
types={
"has_shareholder": [
@@ -564,6 +566,7 @@ class GetEntityResponse(EntityDetails):
"address": 3,
},
reference_id="b4d06d4b77f51fab3c77c9653aabdda4/a80e7f4c-c219-437b-9941-32d89ea5885a/1560542045043:15d813b260619393762864f22d3c5b2d",
+ logistics_entity=False,
),
editable=False,
matches={},
diff --git a/src/sayari/notifications/client.py b/src/sayari/notifications/client.py
index cfd72ec8..28b85819 100644
--- a/src/sayari/notifications/client.py
+++ b/src/sayari/notifications/client.py
@@ -74,7 +74,7 @@ def project_notifications(
client_secret="YOUR_CLIENT_SECRET",
)
client.notifications.project_notifications(
- id="0oZnoG",
+ id="0dLeO0",
limit=20,
)
"""
@@ -684,7 +684,7 @@ async def project_notifications(
async def main() -> None:
await client.notifications.project_notifications(
- id="0oZnoG",
+ id="0dLeO0",
limit=20,
)
diff --git a/src/sayari/notifications/types/project_notification_data.py b/src/sayari/notifications/types/project_notification_data.py
index db70251c..0f382f56 100644
--- a/src/sayari/notifications/types/project_notification_data.py
+++ b/src/sayari/notifications/types/project_notification_data.py
@@ -9,11 +9,6 @@
class ProjectNotificationData(UniversalBaseModel):
- id: str = pydantic.Field()
- """
- The ID of the entity
- """
-
resource_id: str = pydantic.Field()
"""
The ID of the saved resource
@@ -25,7 +20,7 @@ class ProjectNotificationData(UniversalBaseModel):
"""
notifications: typing.List[Notification]
- custom_fields: typing.Optional[typing.Optional[typing.Any]] = pydantic.Field(default=None)
+ custom_fields: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None)
"""
This property is in beta and is subject to change. It is provided for early access and testing purposes only. custom user key/value pairs (key must be prefixed with "custom_" and value must be "string" type)
"""
diff --git a/src/sayari/notifications/types/project_notifications_response.py b/src/sayari/notifications/types/project_notifications_response.py
index 0d369dca..d52eab33 100644
--- a/src/sayari/notifications/types/project_notifications_response.py
+++ b/src/sayari/notifications/types/project_notifications_response.py
@@ -23,95 +23,139 @@ class ProjectNotificationsResponse(UniversalBaseModel):
)
ProjectNotificationsResponse(
- offset=0,
- limit=20,
next=False,
size=QualifiedCount(
- count=3,
+ count=73,
qualifier="eq",
),
data=[
ProjectNotificationData(
- id="dlOL1cZzEkIEZcRUcrBZCQ",
- entity_id="dlOL1cZzEkIEZcRUcrBZCQ",
- resource_id="0eZQ43",
+ resource_id="olxQPZ",
+ entity_id="IoKwj2-82wwzZRlFA1htGQ",
notifications=[
+ Notification(
+ type="risk",
+ field="exports_ilab_child_labor",
+ values=["false"],
+ date="2025-06-04T00:00:00.000Z",
+ ),
+ Notification(
+ type="risk",
+ field="exports_ilab_forced_labor",
+ values=["false"],
+ date="2025-06-04T00:00:00.000Z",
+ ),
Notification(
type="risk",
field="forced_labor_xinjiang_origin_subtier",
+ values=["3"],
+ date="2025-06-04T00:00:00.000Z",
+ ),
+ Notification(
+ type="risk",
+ field="psa_exports_ilab_child_labor",
values=["false"],
- date="2024-02-06T00:00:00.000Z",
- )
+ date="2025-06-04T00:00:00.000Z",
+ ),
+ Notification(
+ type="risk",
+ field="psa_exports_ilab_forced_labor",
+ values=["false"],
+ date="2025-06-04T00:00:00.000Z",
+ ),
],
- custom_fields={"properties": {"custom_name": "Victoria Beckham"}},
+ custom_fields={},
risk_notifications=ProjectNotificationRiskData(
- added=["forced_labor_xinjiang_origin_subtier"],
- removed=[],
- date="2024-02-06T00:00:00.000Z",
+ added=[
+ "exports_ilab_child_labor",
+ "exports_ilab_forced_labor",
+ "psa_exports_ilab_child_labor",
+ "psa_exports_ilab_forced_labor",
+ ],
+ removed=["forced_labor_xinjiang_origin_subtier"],
+ date="2025-06-04T00:00:00.000Z",
),
),
ProjectNotificationData(
- id="wxwqZshCF4trlrmOa2eu9w",
- entity_id="wxwqZshCF4trlrmOa2eu9w",
- resource_id="03ePyj",
+ resource_id="Kx1w34",
+ entity_id="3oKp0fp1UE-W8BG5crAFIw",
notifications=[
Notification(
type="risk",
- field="forced_labor_sheffield_hallam_university_reports_origin_subtier",
- values=["3"],
- date="2024-02-15T00:00:00.000Z",
- )
+ field="exports_ilab_child_labor",
+ values=["true"],
+ date="2025-06-04T00:00:00.000Z",
+ ),
+ Notification(
+ type="risk",
+ field="exports_ilab_forced_labor",
+ values=["true"],
+ date="2025-06-04T00:00:00.000Z",
+ ),
+ Notification(
+ type="risk",
+ field="psa_exports_ilab_child_labor",
+ values=["true"],
+ date="2025-06-04T00:00:00.000Z",
+ ),
+ Notification(
+ type="risk",
+ field="psa_exports_ilab_forced_labor",
+ values=["true"],
+ date="2025-06-04T00:00:00.000Z",
+ ),
],
+ custom_fields={},
risk_notifications=ProjectNotificationRiskData(
added=[],
removed=[
- "forced_labor_sheffield_hallam_university_reports_origin_subtier"
+ "exports_ilab_child_labor",
+ "exports_ilab_forced_labor",
+ "psa_exports_ilab_child_labor",
+ "psa_exports_ilab_forced_labor",
],
- date="2024-02-15T00:00:00.000Z",
+ date="2025-06-04T00:00:00.000Z",
),
),
ProjectNotificationData(
- id="dX9cfM3FPefIp8VAuBKgIQ",
- entity_id="dX9cfM3FPefIp8VAuBKgIQ",
- resource_id="0XEQaX",
+ resource_id="BOMrB9",
+ entity_id="PF0ehzmptuJ2VJr2J5u0nw",
notifications=[
Notification(
type="risk",
- field="owner_of_regulatory_action_entity",
- values=["1"],
- date="2024-02-06T00:00:00.000Z",
- ),
- Notification(
- type="risk",
- field="forced_labor_sheffield_hallam_university_reports_origin_direct",
- values=["1"],
- date="2024-02-15T00:00:00.000Z",
+ field="export_controls_adjacent",
+ values=["true"],
+ date="2025-06-14T00:00:00.000Z",
),
Notification(
type="risk",
- field="forced_labor_sheffield_hallam_university_reports_origin_subtier",
- values=["false"],
- date="2024-02-15T00:00:00.000Z",
+ field="exports_bis_high_priority_items_critical_components_indirect",
+ values=["3"],
+ date="2025-06-14T00:00:00.000Z",
),
],
- custom_fields={"properties": {"custom_identifier": "abc123"}},
+ custom_fields={},
risk_notifications=ProjectNotificationRiskData(
added=[
- "forced_labor_sheffield_hallam_university_reports_origin_subtier"
+ "exports_ilab_child_labor",
+ "exports_ilab_forced_labor",
+ "psa_exports_ilab_child_labor",
+ "psa_exports_ilab_forced_labor",
],
removed=[
- "owner_of_regulatory_action_entity",
- "forced_labor_sheffield_hallam_university_reports_origin_direct",
+ "export_controls_adjacent",
+ "exports_bis_high_priority_items_critical_components_indirect",
+ "psa_exports_bis_high_priority_items_critical_components_indirect",
+ "psa_forced_labor_uflpa_origin_subtier",
+ "psa_regulatory_action",
],
- date="2024-02-15T00:00:00.000Z",
+ date="2025-06-04T00:00:00.000Z",
),
),
],
)
"""
- offset: int
- limit: int
next: bool
data: typing.List[ProjectNotificationData]
size: QualifiedCount
diff --git a/src/sayari/ontology/types/ontology_source.py b/src/sayari/ontology/types/ontology_source.py
index 26881a8e..3ed6ea02 100644
--- a/src/sayari/ontology/types/ontology_source.py
+++ b/src/sayari/ontology/types/ontology_source.py
@@ -4,8 +4,8 @@
from ...generated_types.types.country import Country
import datetime as dt
import pydantic
-from ...core.pydantic_utilities import IS_PYDANTIC_V2
import typing
+from ...core.pydantic_utilities import IS_PYDANTIC_V2
class OntologySource(UniversalBaseModel):
@@ -22,7 +22,7 @@ class OntologySource(UniversalBaseModel):
source_type: str
record_type: str
structure: str
- source_url: str
+ source_url: typing.Optional[str] = None
pep: bool
watchlist: bool
diff --git a/src/sayari/project/__init__.py b/src/sayari/project/__init__.py
index efc4181c..b9acab6e 100644
--- a/src/sayari/project/__init__.py
+++ b/src/sayari/project/__init__.py
@@ -9,9 +9,6 @@
GetProjectEntitiesAcceptHeader,
GetProjectEntitiesResponse,
GetProjectsResponse,
- HsCodeAgg,
- HsCodeAggBucket,
- HsCodeAggTerms,
IntKeyValue,
Project,
ProjectCounts,
@@ -43,9 +40,6 @@
"GetProjectEntitiesAcceptHeader",
"GetProjectEntitiesResponse",
"GetProjectsResponse",
- "HsCodeAgg",
- "HsCodeAggBucket",
- "HsCodeAggTerms",
"IntKeyValue",
"Project",
"ProjectCounts",
diff --git a/src/sayari/project/client.py b/src/sayari/project/client.py
index 2f68712a..6962d3d7 100644
--- a/src/sayari/project/client.py
+++ b/src/sayari/project/client.py
@@ -22,16 +22,8 @@
from json.decoder import JSONDecodeError
from ..core.api_error import ApiError
from .types.get_projects_response import GetProjectsResponse
-from .types.get_project_entities_accept_header import GetProjectEntitiesAcceptHeader
-from ..generated_types.types.entities import Entities
-from .types.sort_field import SortField
-from .types.project_entities_filter import ProjectEntitiesFilter
-from .types.project_entities_aggs_definition import ProjectEntitiesAggsDefinition
-from .types.get_project_entities_response import GetProjectEntitiesResponse
-from ..core.jsonable_encoder import jsonable_encoder
-from ..shared_errors.errors.not_acceptable import NotAcceptable
-from ..shared_errors.types.not_acceptable_response import NotAcceptableResponse
from .types.delete_project_response import DeleteProjectResponse
+from ..core.jsonable_encoder import jsonable_encoder
from ..core.client_wrapper import AsyncClientWrapper
# this is used as the default value for optional parameters
@@ -62,7 +54,7 @@ def create_project(
Examples
--------
from sayari import Sayari
- from sayari.project import CreateProjectRequest
+ from sayari.project import CreateProjectRequest, ProjectShareOnCreate
client = Sayari(
client_id="YOUR_CLIENT_ID",
@@ -70,7 +62,10 @@ def create_project(
)
client.project.create_project(
request=CreateProjectRequest(
- label="Project Alpha",
+ label="My First Project",
+ share=ProjectShareOnCreate(
+ org="admin",
+ ),
),
)
"""
@@ -288,196 +283,6 @@ def get_projects(
raise ApiError(status_code=_response.status_code, body=_response.text)
raise ApiError(status_code=_response.status_code, body=_response_json)
- def get_project_entities(
- self,
- id: str,
- *,
- accept: GetProjectEntitiesAcceptHeader,
- next: typing.Optional[str] = None,
- prev: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- entity_types: typing.Optional[typing.Union[Entities, typing.Sequence[Entities]]] = None,
- geo_facets: typing.Optional[bool] = None,
- hs_codes: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- received_hs_codes: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- shipped_hs_codes: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- combined_hs_codes: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- translation: typing.Optional[str] = None,
- sort: typing.Optional[SortField] = None,
- filters: typing.Optional[typing.Union[ProjectEntitiesFilter, typing.Sequence[ProjectEntitiesFilter]]] = None,
- aggregations: typing.Optional[
- typing.Union[ProjectEntitiesAggsDefinition, typing.Sequence[ProjectEntitiesAggsDefinition]]
- ] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> GetProjectEntitiesResponse:
- """
- This endpoint is deprecated. Retrieve a list of entities in a project.
-
- Parameters
- ----------
- id : str
- The project identifier.
-
- accept : GetProjectEntitiesAcceptHeader
- The response format. Defaults to application/json.
-
- next : typing.Optional[str]
- The pagination token for the next page of entities.
-
- prev : typing.Optional[str]
- The pagination token for the previous page of entities.
-
- limit : typing.Optional[int]
- Limit total entities returned. Defaults to 1,000. Max 10,000.
-
- entity_types : typing.Optional[typing.Union[Entities, typing.Sequence[Entities]]]
- Only return entities of the specified [entity type(s)](/sayari-library/ontology/entities). Defaults to all types.
-
- geo_facets : typing.Optional[bool]
- Whether to include geo facets in the response. Defaults to false.
-
- hs_codes : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Only return entities with the specified HS code(s) in their supply chain.
-
- received_hs_codes : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Only return entities that received the specified HS code(s).
-
- shipped_hs_codes : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Only return entities that shipped the specified HS code(s).
-
- combined_hs_codes : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Only return entities that have shipped or received the specified HS code(s).
-
- translation : typing.Optional[str]
- The language code to translate the entity labels to. Defaults to the user's preferred language.
-
- sort : typing.Optional[SortField]
-
- filters : typing.Optional[typing.Union[ProjectEntitiesFilter, typing.Sequence[ProjectEntitiesFilter]]]
- Filter for entities in a project. The format is `field=value`, where the equal sign is encoded as `%3D`. Supported fields are as follows
-
- aggregations : typing.Optional[typing.Union[ProjectEntitiesAggsDefinition, typing.Sequence[ProjectEntitiesAggsDefinition]]]
- Aggregations that should be returned for entities in the project.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- GetProjectEntitiesResponse
-
- Examples
- --------
- from sayari import Sayari
-
- client = Sayari(
- client_id="YOUR_CLIENT_ID",
- client_secret="YOUR_CLIENT_SECRET",
- )
- client.project.get_project_entities(
- id="gPq6EY",
- accept="application/json",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/projects/{jsonable_encoder(id)}/contents/entity",
- method="GET",
- params={
- "next": next,
- "prev": prev,
- "limit": limit,
- "entity_types": entity_types,
- "geo_facets": geo_facets,
- "hs_codes": hs_codes,
- "received_hs_codes": received_hs_codes,
- "shipped_hs_codes": shipped_hs_codes,
- "combined_hs_codes": combined_hs_codes,
- "translation": translation,
- "sort": sort,
- "filters": convert_and_respect_annotation_metadata(
- object_=filters, annotation=ProjectEntitiesFilter, direction="write"
- ),
- "aggregations": aggregations,
- },
- headers={
- "Accept": str(accept) if accept is not None else None,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- GetProjectEntitiesResponse,
- parse_obj_as(
- type_=GetProjectEntitiesResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- if _response.status_code == 400:
- raise BadRequest(
- typing.cast(
- BadRequestResponse,
- parse_obj_as(
- type_=BadRequestResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- )
- if _response.status_code == 401:
- raise Unauthorized(
- typing.cast(
- UnauthorizedResponse,
- parse_obj_as(
- type_=UnauthorizedResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- )
- if _response.status_code == 405:
- raise MethodNotAllowed(
- typing.cast(
- MethodNotAllowedResponse,
- parse_obj_as(
- type_=MethodNotAllowedResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- )
- if _response.status_code == 406:
- raise NotAcceptable(
- typing.cast(
- NotAcceptableResponse,
- parse_obj_as(
- type_=NotAcceptableResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- )
- if _response.status_code == 429:
- raise RateLimitExceeded(
- typing.cast(
- RateLimitResponse,
- parse_obj_as(
- type_=RateLimitResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- )
- if _response.status_code == 500:
- raise InternalServerError(
- typing.cast(
- InternalServerErrorResponse,
- parse_obj_as(
- type_=InternalServerErrorResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, body=_response.text)
- raise ApiError(status_code=_response.status_code, body=_response_json)
-
def delete_project(
self, project_id: str, *, request_options: typing.Optional[RequestOptions] = None
) -> DeleteProjectResponse:
@@ -613,7 +418,7 @@ async def create_project(
import asyncio
from sayari import AsyncSayari
- from sayari.project import CreateProjectRequest
+ from sayari.project import CreateProjectRequest, ProjectShareOnCreate
client = AsyncSayari(
client_id="YOUR_CLIENT_ID",
@@ -624,7 +429,10 @@ async def create_project(
async def main() -> None:
await client.project.create_project(
request=CreateProjectRequest(
- label="Project Alpha",
+ label="My First Project",
+ share=ProjectShareOnCreate(
+ org="admin",
+ ),
),
)
@@ -853,204 +661,6 @@ async def main() -> None:
raise ApiError(status_code=_response.status_code, body=_response.text)
raise ApiError(status_code=_response.status_code, body=_response_json)
- async def get_project_entities(
- self,
- id: str,
- *,
- accept: GetProjectEntitiesAcceptHeader,
- next: typing.Optional[str] = None,
- prev: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- entity_types: typing.Optional[typing.Union[Entities, typing.Sequence[Entities]]] = None,
- geo_facets: typing.Optional[bool] = None,
- hs_codes: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- received_hs_codes: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- shipped_hs_codes: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- combined_hs_codes: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- translation: typing.Optional[str] = None,
- sort: typing.Optional[SortField] = None,
- filters: typing.Optional[typing.Union[ProjectEntitiesFilter, typing.Sequence[ProjectEntitiesFilter]]] = None,
- aggregations: typing.Optional[
- typing.Union[ProjectEntitiesAggsDefinition, typing.Sequence[ProjectEntitiesAggsDefinition]]
- ] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> GetProjectEntitiesResponse:
- """
- This endpoint is deprecated. Retrieve a list of entities in a project.
-
- Parameters
- ----------
- id : str
- The project identifier.
-
- accept : GetProjectEntitiesAcceptHeader
- The response format. Defaults to application/json.
-
- next : typing.Optional[str]
- The pagination token for the next page of entities.
-
- prev : typing.Optional[str]
- The pagination token for the previous page of entities.
-
- limit : typing.Optional[int]
- Limit total entities returned. Defaults to 1,000. Max 10,000.
-
- entity_types : typing.Optional[typing.Union[Entities, typing.Sequence[Entities]]]
- Only return entities of the specified [entity type(s)](/sayari-library/ontology/entities). Defaults to all types.
-
- geo_facets : typing.Optional[bool]
- Whether to include geo facets in the response. Defaults to false.
-
- hs_codes : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Only return entities with the specified HS code(s) in their supply chain.
-
- received_hs_codes : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Only return entities that received the specified HS code(s).
-
- shipped_hs_codes : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Only return entities that shipped the specified HS code(s).
-
- combined_hs_codes : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Only return entities that have shipped or received the specified HS code(s).
-
- translation : typing.Optional[str]
- The language code to translate the entity labels to. Defaults to the user's preferred language.
-
- sort : typing.Optional[SortField]
-
- filters : typing.Optional[typing.Union[ProjectEntitiesFilter, typing.Sequence[ProjectEntitiesFilter]]]
- Filter for entities in a project. The format is `field=value`, where the equal sign is encoded as `%3D`. Supported fields are as follows
-
- aggregations : typing.Optional[typing.Union[ProjectEntitiesAggsDefinition, typing.Sequence[ProjectEntitiesAggsDefinition]]]
- Aggregations that should be returned for entities in the project.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- GetProjectEntitiesResponse
-
- Examples
- --------
- import asyncio
-
- from sayari import AsyncSayari
-
- client = AsyncSayari(
- client_id="YOUR_CLIENT_ID",
- client_secret="YOUR_CLIENT_SECRET",
- )
-
-
- async def main() -> None:
- await client.project.get_project_entities(
- id="gPq6EY",
- accept="application/json",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/projects/{jsonable_encoder(id)}/contents/entity",
- method="GET",
- params={
- "next": next,
- "prev": prev,
- "limit": limit,
- "entity_types": entity_types,
- "geo_facets": geo_facets,
- "hs_codes": hs_codes,
- "received_hs_codes": received_hs_codes,
- "shipped_hs_codes": shipped_hs_codes,
- "combined_hs_codes": combined_hs_codes,
- "translation": translation,
- "sort": sort,
- "filters": convert_and_respect_annotation_metadata(
- object_=filters, annotation=ProjectEntitiesFilter, direction="write"
- ),
- "aggregations": aggregations,
- },
- headers={
- "Accept": str(accept) if accept is not None else None,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- GetProjectEntitiesResponse,
- parse_obj_as(
- type_=GetProjectEntitiesResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- if _response.status_code == 400:
- raise BadRequest(
- typing.cast(
- BadRequestResponse,
- parse_obj_as(
- type_=BadRequestResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- )
- if _response.status_code == 401:
- raise Unauthorized(
- typing.cast(
- UnauthorizedResponse,
- parse_obj_as(
- type_=UnauthorizedResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- )
- if _response.status_code == 405:
- raise MethodNotAllowed(
- typing.cast(
- MethodNotAllowedResponse,
- parse_obj_as(
- type_=MethodNotAllowedResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- )
- if _response.status_code == 406:
- raise NotAcceptable(
- typing.cast(
- NotAcceptableResponse,
- parse_obj_as(
- type_=NotAcceptableResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- )
- if _response.status_code == 429:
- raise RateLimitExceeded(
- typing.cast(
- RateLimitResponse,
- parse_obj_as(
- type_=RateLimitResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- )
- if _response.status_code == 500:
- raise InternalServerError(
- typing.cast(
- InternalServerErrorResponse,
- parse_obj_as(
- type_=InternalServerErrorResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, body=_response.text)
- raise ApiError(status_code=_response.status_code, body=_response_json)
-
async def delete_project(
self, project_id: str, *, request_options: typing.Optional[RequestOptions] = None
) -> DeleteProjectResponse:
diff --git a/src/sayari/project/types/__init__.py b/src/sayari/project/types/__init__.py
index 7e7758a6..069aeaa3 100644
--- a/src/sayari/project/types/__init__.py
+++ b/src/sayari/project/types/__init__.py
@@ -8,9 +8,6 @@
from .get_project_entities_accept_header import GetProjectEntitiesAcceptHeader
from .get_project_entities_response import GetProjectEntitiesResponse
from .get_projects_response import GetProjectsResponse
-from .hs_code_agg import HsCodeAgg
-from .hs_code_agg_bucket import HsCodeAggBucket
-from .hs_code_agg_terms import HsCodeAggTerms
from .int_key_value import IntKeyValue
from .project import Project
from .project_counts import ProjectCounts
@@ -41,9 +38,6 @@
"GetProjectEntitiesAcceptHeader",
"GetProjectEntitiesResponse",
"GetProjectsResponse",
- "HsCodeAgg",
- "HsCodeAggBucket",
- "HsCodeAggTerms",
"IntKeyValue",
"Project",
"ProjectCounts",
diff --git a/src/sayari/project/types/bucket_agg.py b/src/sayari/project/types/bucket_agg.py
index 7ec68f19..8bd37aff 100644
--- a/src/sayari/project/types/bucket_agg.py
+++ b/src/sayari/project/types/bucket_agg.py
@@ -2,7 +2,6 @@
from ...core.pydantic_utilities import UniversalBaseModel
import typing
-from .int_key_value import IntKeyValue
from ...core.pydantic_utilities import IS_PYDANTIC_V2
import pydantic
@@ -16,7 +15,6 @@ class BucketAgg(UniversalBaseModel):
doc_count: int
label: typing.Optional[str] = None
comment: typing.Optional[str] = None
- hs_code_sums: typing.Optional[IntKeyValue] = 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/sayari/project/types/create_project_request.py b/src/sayari/project/types/create_project_request.py
index f12c8c80..a35ec56e 100644
--- a/src/sayari/project/types/create_project_request.py
+++ b/src/sayari/project/types/create_project_request.py
@@ -11,10 +11,13 @@ class CreateProjectRequest(UniversalBaseModel):
"""
Examples
--------
- from sayari.project import CreateProjectRequest
+ from sayari.project import CreateProjectRequest, ProjectShareOnCreate
CreateProjectRequest(
- label="Project Alpha",
+ label="My First Project",
+ share=ProjectShareOnCreate(
+ org="admin",
+ ),
)
"""
diff --git a/src/sayari/project/types/create_project_response.py b/src/sayari/project/types/create_project_response.py
index 6667dca8..8ba9371f 100644
--- a/src/sayari/project/types/create_project_response.py
+++ b/src/sayari/project/types/create_project_response.py
@@ -15,17 +15,18 @@ class CreateProjectResponse(UniversalBaseModel):
CreateProjectResponse(
data=Project(
- id="YVMBRg",
- label="Project Alpha",
+ id="0pjjaB",
+ label="My First Project",
archived=False,
- created="2024-03-15 20:31:06.08855+00",
- updated="2024-03-15 20:31:06.08855+00",
+ created="2025-08-26 03:17:58.70405+00",
+ updated="2025-08-26 03:17:58.70405+00",
counts=ProjectCounts(
entity=0,
graph=0,
record=0,
search=0,
),
+ is_scrm=False,
),
)
"""
diff --git a/src/sayari/project/types/get_project_entities_response.py b/src/sayari/project/types/get_project_entities_response.py
index b16974dc..a6fc46ba 100644
--- a/src/sayari/project/types/get_project_entities_response.py
+++ b/src/sayari/project/types/get_project_entities_response.py
@@ -16,9 +16,6 @@ class GetProjectEntitiesResponse(PaginatedResponse):
from sayari.project import (
BucketAgg,
GetProjectEntitiesResponse,
- HsCodeAgg,
- HsCodeAggBucket,
- HsCodeAggTerms,
IntKeyValue,
ProjectEntitiesAggs,
ProjectEntity,
@@ -321,29 +318,7 @@ class GetProjectEntitiesResponse(PaginatedResponse):
doc_count=3,
),
],
- received_hs_codes=HsCodeAgg(
- doc_count=2,
- hs_code_terms=HsCodeAggTerms(
- doc_count_error_upper_bound=0,
- sum_other_doc_count=0,
- buckets=[
- HsCodeAggBucket(
- key="271290",
- doc_count=1,
- hs_code_sums=IntKeyValue(
- value=4,
- ),
- ),
- HsCodeAggBucket(
- key="271220",
- doc_count=1,
- hs_code_sums=IntKeyValue(
- value=1,
- ),
- ),
- ],
- ),
- ),
+ received_hs_codes=["271290", "271220"],
custom_fields=[
BucketAgg(
key="custom_id1",
@@ -371,37 +346,7 @@ class GetProjectEntitiesResponse(PaginatedResponse):
"eu_high_risk_third": {"tier4": 1},
"export_to_soe": {"tier1": 1, "tier3": 1, "tier4": 2},
},
- shipped_hs_codes=HsCodeAgg(
- doc_count=0,
- hs_code_terms=HsCodeAggTerms(
- doc_count_error_upper_bound=0,
- sum_other_doc_count=0,
- buckets=[],
- ),
- ),
- combined_hs_codes=HsCodeAgg(
- doc_count=2,
- hs_code_terms=HsCodeAggTerms(
- doc_count_error_upper_bound=0,
- sum_other_doc_count=0,
- buckets=[
- HsCodeAggBucket(
- key="271290",
- doc_count=1,
- hs_code_sums=IntKeyValue(
- value=4,
- ),
- ),
- HsCodeAggBucket(
- key="271220",
- doc_count=1,
- hs_code_sums=IntKeyValue(
- value=1,
- ),
- ),
- ],
- ),
- ),
+ combined_hs_codes=["271290", "271220"],
),
)
"""
diff --git a/src/sayari/project/types/project.py b/src/sayari/project/types/project.py
index 1ee4a2a7..55dc9eaf 100644
--- a/src/sayari/project/types/project.py
+++ b/src/sayari/project/types/project.py
@@ -3,8 +3,8 @@
from ...core.pydantic_utilities import UniversalBaseModel
import pydantic
from .project_counts import ProjectCounts
-from ...core.pydantic_utilities import IS_PYDANTIC_V2
import typing
+from ...core.pydantic_utilities import IS_PYDANTIC_V2
class Project(UniversalBaseModel):
@@ -26,6 +26,7 @@ class Project(UniversalBaseModel):
created: str
updated: str
counts: ProjectCounts
+ is_scrm: typing.Optional[bool] = 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/sayari/project/types/project_entities_aggs.py b/src/sayari/project/types/project_entities_aggs.py
index 1da4ee28..cb231c2d 100644
--- a/src/sayari/project/types/project_entities_aggs.py
+++ b/src/sayari/project/types/project_entities_aggs.py
@@ -4,7 +4,6 @@
import typing
from .bucket_agg import BucketAgg
from .tier_count_agg import TierCountAgg
-from .hs_code_agg import HsCodeAgg
from .int_key_value import IntKeyValue
from ...core.pydantic_utilities import IS_PYDANTIC_V2
import pydantic
@@ -27,9 +26,9 @@ class ProjectEntitiesAggs(UniversalBaseModel):
tag_ids: typing.Optional[typing.List[BucketAgg]] = None
case_statuses: typing.Optional[typing.List[BucketAgg]] = None
shipment_counts: typing.Optional[typing.List[BucketAgg]] = None
- shipped_hs_codes: typing.Optional[HsCodeAgg] = None
- received_hs_codes: typing.Optional[HsCodeAgg] = None
- combined_hs_codes: typing.Optional[HsCodeAgg] = None
+ shipped_hs_codes: typing.Optional[typing.List[str]] = None
+ received_hs_codes: typing.Optional[typing.List[str]] = None
+ combined_hs_codes: typing.Optional[typing.List[str]] = None
match_results: typing.Optional[typing.List[BucketAgg]] = None
custom_fields: typing.Optional[typing.List[BucketAgg]] = None
custom_fields_count: typing.Optional[IntKeyValue] = None
diff --git a/src/sayari/project/types/project_entities_filter.py b/src/sayari/project/types/project_entities_filter.py
index d8cb726b..5fd228a6 100644
--- a/src/sayari/project/types/project_entities_filter.py
+++ b/src/sayari/project/types/project_entities_filter.py
@@ -49,13 +49,6 @@ class ProjectEntitiesFilter(UniversalBaseModel):
Filter by upstream (supply chain) [country](/sayari-library/ontology/enumerated-types#country) at any tier.
"""
- tier_0_shipment_country: typing_extensions.Annotated[
- typing.Optional[typing.List[Country]], FieldMetadata(alias="tier0_shipment_country")
- ] = pydantic.Field(default=None)
- """
- Filter by [country](/sayari-library/ontology/enumerated-types#country) at tier 0.
- """
-
tier_1_shipment_country: typing_extensions.Annotated[
typing.Optional[typing.List[Country]], FieldMetadata(alias="tier1_shipment_country")
] = pydantic.Field(default=None)
@@ -84,6 +77,13 @@ class ProjectEntitiesFilter(UniversalBaseModel):
Filter by upstream (supply chain) [country](/sayari-library/ontology/enumerated-types#country) at tier 4.
"""
+ tier_5_shipment_country: typing_extensions.Annotated[
+ typing.Optional[typing.List[Country]], FieldMetadata(alias="tier5_shipment_country")
+ ] = pydantic.Field(default=None)
+ """
+ Filter by upstream (supply chain) [country](/sayari-library/ontology/enumerated-types#country) at tier 5.
+ """
+
business_purpose: typing.Optional[typing.List[str]] = pydantic.Field(default=None)
"""
Filter by HS code, HS code description, or business description.
diff --git a/src/sayari/project_entity/__init__.py b/src/sayari/project_entity/__init__.py
index 82f696dc..add92aca 100644
--- a/src/sayari/project_entity/__init__.py
+++ b/src/sayari/project_entity/__init__.py
@@ -5,14 +5,18 @@
AttributeType,
AttributeTypesResponse,
AttributeValues,
+ AttributesResponse,
BusinessPurpose,
CaseStatus,
CountType,
CreateResolvedProjectEntityRequest,
FacetBucket,
FacetsResponse,
+ GroupedAttribute,
+ GroupedAttributeValue,
Location,
- MatchResult,
+ MatchCount,
+ MatchProfileEnum,
MatchStrengthEnum,
MatchedAttributes,
ProductBucket,
@@ -26,6 +30,7 @@
ProjectEntitySupplyChainSummaryResponse,
ProjectEntitySupplyChainSummaryResponseData,
ProjectEntitySupplyChainUpstream,
+ ProjectRiskCategory,
ProjectRiskFactor,
ResolutionAttributes,
ResolutionProfile,
@@ -50,14 +55,18 @@
"AttributeType",
"AttributeTypesResponse",
"AttributeValues",
+ "AttributesResponse",
"BusinessPurpose",
"CaseStatus",
"CountType",
"CreateResolvedProjectEntityRequest",
"FacetBucket",
"FacetsResponse",
+ "GroupedAttribute",
+ "GroupedAttributeValue",
"Location",
- "MatchResult",
+ "MatchCount",
+ "MatchProfileEnum",
"MatchStrengthEnum",
"MatchedAttributes",
"ProductBucket",
@@ -71,6 +80,7 @@
"ProjectEntitySupplyChainSummaryResponse",
"ProjectEntitySupplyChainSummaryResponseData",
"ProjectEntitySupplyChainUpstream",
+ "ProjectRiskCategory",
"ProjectRiskFactor",
"ResolutionAttributes",
"ResolutionProfile",
diff --git a/src/sayari/project_entity/client.py b/src/sayari/project_entity/client.py
index 975b9423..83281508 100644
--- a/src/sayari/project_entity/client.py
+++ b/src/sayari/project_entity/client.py
@@ -23,7 +23,7 @@
from json.decoder import JSONDecodeError
from ..core.api_error import ApiError
from .types.case_status import CaseStatus
-from .types.match_result import MatchResult
+from .types.match_count import MatchCount
from .types.match_strength_enum import MatchStrengthEnum
from ..generated_types.types.risk import Risk
from ..generated_types.types.risk_category import RiskCategory
@@ -178,8 +178,8 @@ def get_project_entities(
uploads: typing.Optional[typing.Sequence[str]] = None,
case_status: typing.Optional[typing.Sequence[CaseStatus]] = None,
tags: typing.Optional[typing.Sequence[str]] = None,
- match_result: typing.Optional[typing.Sequence[MatchResult]] = None,
- match_strength_v_1: typing.Optional[typing.Sequence[MatchStrengthEnum]] = None,
+ match_count: typing.Optional[MatchCount] = None,
+ match_strength: typing.Optional[typing.Sequence[MatchStrengthEnum]] = None,
entity_types: typing.Optional[typing.Sequence[str]] = None,
geo_facets: typing.Optional[bool] = None,
exact_match: typing.Optional[bool] = None,
@@ -215,10 +215,10 @@ def get_project_entities(
tags : typing.Optional[typing.Sequence[str]]
Filter by tag IDs
- match_result : typing.Optional[typing.Sequence[MatchResult]]
- Filter by match result
+ match_count : typing.Optional[MatchCount]
+ Filter by match count
- match_strength_v_1 : typing.Optional[typing.Sequence[MatchStrengthEnum]]
+ match_strength : typing.Optional[typing.Sequence[MatchStrengthEnum]]
Filter by match strength
entity_types : typing.Optional[typing.Sequence[str]]
@@ -290,8 +290,8 @@ def get_project_entities(
"uploads": uploads,
"case_status": case_status,
"tags": tags,
- "match_result": match_result,
- "match_strength_v1": match_strength_v_1,
+ "match_count": match_count,
+ "match_strength": match_strength,
"entity_types": entity_types,
"geo_facets": geo_facets,
"exact_match": exact_match,
@@ -392,8 +392,8 @@ def get_project_entity(
uploads: typing.Optional[typing.Sequence[str]] = None,
case_status: typing.Optional[typing.Sequence[CaseStatus]] = None,
tags: typing.Optional[typing.Sequence[str]] = None,
- match_result: typing.Optional[typing.Sequence[MatchResult]] = None,
- match_strength_v_1: typing.Optional[typing.Sequence[MatchStrengthEnum]] = None,
+ match_count: typing.Optional[MatchCount] = None,
+ match_strength: typing.Optional[typing.Sequence[MatchStrengthEnum]] = None,
entity_types: typing.Optional[typing.Sequence[str]] = None,
risk: typing.Optional[typing.Sequence[Risk]] = None,
risk_category: typing.Optional[typing.Sequence[RiskCategory]] = None,
@@ -420,10 +420,10 @@ def get_project_entity(
tags : typing.Optional[typing.Sequence[str]]
Filter by tag IDs
- match_result : typing.Optional[typing.Sequence[MatchResult]]
- Filter by match result
+ match_count : typing.Optional[MatchCount]
+ Filter by match count
- match_strength_v_1 : typing.Optional[typing.Sequence[MatchStrengthEnum]]
+ match_strength : typing.Optional[typing.Sequence[MatchStrengthEnum]]
Filter by match strength
entity_types : typing.Optional[typing.Sequence[str]]
@@ -463,8 +463,8 @@ def get_project_entity(
"uploads": uploads,
"case_status": case_status,
"tags": tags,
- "match_result": match_result,
- "match_strength_v1": match_strength_v_1,
+ "match_count": match_count,
+ "match_strength": match_strength,
"entity_types": entity_types,
"risk": risk,
"risk_category": risk_category,
@@ -1014,6 +1014,8 @@ def project_entity_supply_chain(
project_id: str,
project_entity_id: str,
*,
+ product: typing.Optional[typing.Sequence[str]] = None,
+ not_product: typing.Optional[typing.Sequence[str]] = None,
risk: typing.Optional[typing.Sequence[Risk]] = None,
not_risk: typing.Optional[typing.Sequence[Risk]] = None,
countries: typing.Optional[typing.Sequence[Country]] = None,
@@ -1025,8 +1027,6 @@ def project_entity_supply_chain(
tier_3_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
tier_4_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
tier_5_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
- product: typing.Optional[typing.Sequence[str]] = None,
- not_product: typing.Optional[typing.Sequence[str]] = None,
component: typing.Optional[typing.Sequence[str]] = None,
not_component: typing.Optional[typing.Sequence[str]] = None,
min_date: typing.Optional[str] = None,
@@ -1046,6 +1046,12 @@ def project_entity_supply_chain(
project_entity_id : str
The project entity Identifier
+ product : typing.Optional[typing.Sequence[str]]
+ Product root edge filter. Filters results to include only trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.
+
+ not_product : typing.Optional[typing.Sequence[str]]
+ Product root edge filter. Filters results to exclude any trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.
+
risk : typing.Optional[typing.Sequence[Risk]]
Risk leaf node filter. Only return supply chains that end with a supplier that has 1+ of the specified risk factors.
@@ -1079,12 +1085,6 @@ def project_entity_supply_chain(
tier_5_shipment_country : typing.Optional[typing.Sequence[Country]]
Filters supply chain paths where 1+ shipment country from tier 5 matches the provided values.
- product : typing.Optional[typing.Sequence[str]]
- Product root edge filter. Only return supply chains that start with an edge that has 1+ of the specified HS codes.
-
- not_product : typing.Optional[typing.Sequence[str]]
- Product root edge filter. Only return supply chains that start with an edge that has none of the specified HS codes.
-
component : typing.Optional[typing.Sequence[str]]
Component edge filter. Only return supply chains that contain at least one edge with 1+ of the specified HS codes.
@@ -1119,17 +1119,18 @@ def project_entity_supply_chain(
client_secret="YOUR_CLIENT_SECRET",
)
client.project_entity.project_entity_supply_chain(
- project_id="Gam5qG",
- project_entity_id="GOeOE8",
- min_date="2023-03-15",
- product=["3204"],
- risk=["forced_labor_xinjiang_origin_subtier"],
+ project_id="0n4473",
+ project_entity_id="yebNPJ",
+ product=["6004"],
+ limit=1,
)
"""
_response = self._client_wrapper.httpx_client.request(
f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/supply_chain/upstream",
method="GET",
params={
+ "product": product,
+ "-product": not_product,
"risk": risk,
"-risk": not_risk,
"countries": countries,
@@ -1141,8 +1142,6 @@ def project_entity_supply_chain(
"tier3_shipment_country": tier_3_shipment_country,
"tier4_shipment_country": tier_4_shipment_country,
"tier5_shipment_country": tier_5_shipment_country,
- "product": product,
- "-product": not_product,
"component": component,
"-component": not_component,
"min_date": min_date,
@@ -1231,12 +1230,12 @@ def project_entity_supply_chain_summary(
project_id: str,
project_entity_id: str,
*,
+ product: typing.Optional[typing.Sequence[str]] = None,
+ not_product: typing.Optional[typing.Sequence[str]] = None,
risk_factors: typing.Optional[typing.Sequence[Risk]] = None,
not_risk: typing.Optional[typing.Sequence[Risk]] = None,
countries: typing.Optional[typing.Sequence[Country]] = None,
not_countries: typing.Optional[typing.Sequence[Country]] = None,
- product: typing.Optional[typing.Sequence[str]] = None,
- not_product: typing.Optional[typing.Sequence[str]] = None,
component: typing.Optional[typing.Sequence[str]] = None,
not_component: typing.Optional[typing.Sequence[str]] = None,
min_date: typing.Optional[str] = None,
@@ -1256,6 +1255,12 @@ def project_entity_supply_chain_summary(
project_entity_id : str
The project entity Identifier
+ product : typing.Optional[typing.Sequence[str]]
+ Product root edge filter. Filters results to include only trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.
+
+ not_product : typing.Optional[typing.Sequence[str]]
+ Product root edge filter. Filters results to exclude any trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.
+
risk_factors : typing.Optional[typing.Sequence[Risk]]
Risk leaf node filter. Only return supply chains that end with a supplier that has 1+ of the specified risk factors.
@@ -1268,12 +1273,6 @@ def project_entity_supply_chain_summary(
not_countries : typing.Optional[typing.Sequence[Country]]
Country leaf node filter. Only return supply chains that end with a supplier in none of the specified countries.
- product : typing.Optional[typing.Sequence[str]]
- Product root edge filter. Only return supply chains that start with an edge that has 1+ of the specified HS codes.
-
- not_product : typing.Optional[typing.Sequence[str]]
- Product root edge filter. Only return supply chains that start with an edge that has none of the specified HS codes.
-
component : typing.Optional[typing.Sequence[str]]
Component edge filter. Only return supply chains that contain at least one edge with 1+ of the specified HS codes.
@@ -1308,29 +1307,21 @@ def project_entity_supply_chain_summary(
client_secret="YOUR_CLIENT_SECRET",
)
client.project_entity.project_entity_supply_chain_summary(
- project_id="Gam5qG",
- project_entity_id="GOeOE8",
- min_date="2023-03-15",
- product=["8536", "8544", "4016"],
- risk_factors=[
- "forced_labor_xinjiang_name",
- "forced_labor_xinjiang_uflpa",
- "forced_labor_uflpa_origin_direct",
- "exports_russian_gold",
- "export_to_sanctioned",
- ],
+ project_id="0n4473",
+ project_entity_id="yebNPJ",
+ max_depth=4,
)
"""
_response = self._client_wrapper.httpx_client.request(
f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/supply_chain/upstream_summary",
method="GET",
params={
+ "product": product,
+ "-product": not_product,
"risk_factors": risk_factors,
"-risk_factors": not_risk,
"countries": countries,
"-countries": not_countries,
- "product": product,
- "-product": not_product,
"component": component,
"-component": not_component,
"min_date": min_date,
@@ -1561,8 +1552,8 @@ async def get_project_entities(
uploads: typing.Optional[typing.Sequence[str]] = None,
case_status: typing.Optional[typing.Sequence[CaseStatus]] = None,
tags: typing.Optional[typing.Sequence[str]] = None,
- match_result: typing.Optional[typing.Sequence[MatchResult]] = None,
- match_strength_v_1: typing.Optional[typing.Sequence[MatchStrengthEnum]] = None,
+ match_count: typing.Optional[MatchCount] = None,
+ match_strength: typing.Optional[typing.Sequence[MatchStrengthEnum]] = None,
entity_types: typing.Optional[typing.Sequence[str]] = None,
geo_facets: typing.Optional[bool] = None,
exact_match: typing.Optional[bool] = None,
@@ -1598,10 +1589,10 @@ async def get_project_entities(
tags : typing.Optional[typing.Sequence[str]]
Filter by tag IDs
- match_result : typing.Optional[typing.Sequence[MatchResult]]
- Filter by match result
+ match_count : typing.Optional[MatchCount]
+ Filter by match count
- match_strength_v_1 : typing.Optional[typing.Sequence[MatchStrengthEnum]]
+ match_strength : typing.Optional[typing.Sequence[MatchStrengthEnum]]
Filter by match strength
entity_types : typing.Optional[typing.Sequence[str]]
@@ -1681,8 +1672,8 @@ async def main() -> None:
"uploads": uploads,
"case_status": case_status,
"tags": tags,
- "match_result": match_result,
- "match_strength_v1": match_strength_v_1,
+ "match_count": match_count,
+ "match_strength": match_strength,
"entity_types": entity_types,
"geo_facets": geo_facets,
"exact_match": exact_match,
@@ -1783,8 +1774,8 @@ async def get_project_entity(
uploads: typing.Optional[typing.Sequence[str]] = None,
case_status: typing.Optional[typing.Sequence[CaseStatus]] = None,
tags: typing.Optional[typing.Sequence[str]] = None,
- match_result: typing.Optional[typing.Sequence[MatchResult]] = None,
- match_strength_v_1: typing.Optional[typing.Sequence[MatchStrengthEnum]] = None,
+ match_count: typing.Optional[MatchCount] = None,
+ match_strength: typing.Optional[typing.Sequence[MatchStrengthEnum]] = None,
entity_types: typing.Optional[typing.Sequence[str]] = None,
risk: typing.Optional[typing.Sequence[Risk]] = None,
risk_category: typing.Optional[typing.Sequence[RiskCategory]] = None,
@@ -1811,10 +1802,10 @@ async def get_project_entity(
tags : typing.Optional[typing.Sequence[str]]
Filter by tag IDs
- match_result : typing.Optional[typing.Sequence[MatchResult]]
- Filter by match result
+ match_count : typing.Optional[MatchCount]
+ Filter by match count
- match_strength_v_1 : typing.Optional[typing.Sequence[MatchStrengthEnum]]
+ match_strength : typing.Optional[typing.Sequence[MatchStrengthEnum]]
Filter by match strength
entity_types : typing.Optional[typing.Sequence[str]]
@@ -1862,8 +1853,8 @@ async def main() -> None:
"uploads": uploads,
"case_status": case_status,
"tags": tags,
- "match_result": match_result,
- "match_strength_v1": match_strength_v_1,
+ "match_count": match_count,
+ "match_strength": match_strength,
"entity_types": entity_types,
"risk": risk,
"risk_category": risk_category,
@@ -2445,6 +2436,8 @@ async def project_entity_supply_chain(
project_id: str,
project_entity_id: str,
*,
+ product: typing.Optional[typing.Sequence[str]] = None,
+ not_product: typing.Optional[typing.Sequence[str]] = None,
risk: typing.Optional[typing.Sequence[Risk]] = None,
not_risk: typing.Optional[typing.Sequence[Risk]] = None,
countries: typing.Optional[typing.Sequence[Country]] = None,
@@ -2456,8 +2449,6 @@ async def project_entity_supply_chain(
tier_3_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
tier_4_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
tier_5_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
- product: typing.Optional[typing.Sequence[str]] = None,
- not_product: typing.Optional[typing.Sequence[str]] = None,
component: typing.Optional[typing.Sequence[str]] = None,
not_component: typing.Optional[typing.Sequence[str]] = None,
min_date: typing.Optional[str] = None,
@@ -2477,6 +2468,12 @@ async def project_entity_supply_chain(
project_entity_id : str
The project entity Identifier
+ product : typing.Optional[typing.Sequence[str]]
+ Product root edge filter. Filters results to include only trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.
+
+ not_product : typing.Optional[typing.Sequence[str]]
+ Product root edge filter. Filters results to exclude any trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.
+
risk : typing.Optional[typing.Sequence[Risk]]
Risk leaf node filter. Only return supply chains that end with a supplier that has 1+ of the specified risk factors.
@@ -2510,12 +2507,6 @@ async def project_entity_supply_chain(
tier_5_shipment_country : typing.Optional[typing.Sequence[Country]]
Filters supply chain paths where 1+ shipment country from tier 5 matches the provided values.
- product : typing.Optional[typing.Sequence[str]]
- Product root edge filter. Only return supply chains that start with an edge that has 1+ of the specified HS codes.
-
- not_product : typing.Optional[typing.Sequence[str]]
- Product root edge filter. Only return supply chains that start with an edge that has none of the specified HS codes.
-
component : typing.Optional[typing.Sequence[str]]
Component edge filter. Only return supply chains that contain at least one edge with 1+ of the specified HS codes.
@@ -2555,11 +2546,10 @@ async def project_entity_supply_chain(
async def main() -> None:
await client.project_entity.project_entity_supply_chain(
- project_id="Gam5qG",
- project_entity_id="GOeOE8",
- min_date="2023-03-15",
- product=["3204"],
- risk=["forced_labor_xinjiang_origin_subtier"],
+ project_id="0n4473",
+ project_entity_id="yebNPJ",
+ product=["6004"],
+ limit=1,
)
@@ -2569,6 +2559,8 @@ async def main() -> None:
f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/supply_chain/upstream",
method="GET",
params={
+ "product": product,
+ "-product": not_product,
"risk": risk,
"-risk": not_risk,
"countries": countries,
@@ -2580,8 +2572,6 @@ async def main() -> None:
"tier3_shipment_country": tier_3_shipment_country,
"tier4_shipment_country": tier_4_shipment_country,
"tier5_shipment_country": tier_5_shipment_country,
- "product": product,
- "-product": not_product,
"component": component,
"-component": not_component,
"min_date": min_date,
@@ -2670,12 +2660,12 @@ async def project_entity_supply_chain_summary(
project_id: str,
project_entity_id: str,
*,
+ product: typing.Optional[typing.Sequence[str]] = None,
+ not_product: typing.Optional[typing.Sequence[str]] = None,
risk_factors: typing.Optional[typing.Sequence[Risk]] = None,
not_risk: typing.Optional[typing.Sequence[Risk]] = None,
countries: typing.Optional[typing.Sequence[Country]] = None,
not_countries: typing.Optional[typing.Sequence[Country]] = None,
- product: typing.Optional[typing.Sequence[str]] = None,
- not_product: typing.Optional[typing.Sequence[str]] = None,
component: typing.Optional[typing.Sequence[str]] = None,
not_component: typing.Optional[typing.Sequence[str]] = None,
min_date: typing.Optional[str] = None,
@@ -2695,6 +2685,12 @@ async def project_entity_supply_chain_summary(
project_entity_id : str
The project entity Identifier
+ product : typing.Optional[typing.Sequence[str]]
+ Product root edge filter. Filters results to include only trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.
+
+ not_product : typing.Optional[typing.Sequence[str]]
+ Product root edge filter. Filters results to exclude any trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.
+
risk_factors : typing.Optional[typing.Sequence[Risk]]
Risk leaf node filter. Only return supply chains that end with a supplier that has 1+ of the specified risk factors.
@@ -2707,12 +2703,6 @@ async def project_entity_supply_chain_summary(
not_countries : typing.Optional[typing.Sequence[Country]]
Country leaf node filter. Only return supply chains that end with a supplier in none of the specified countries.
- product : typing.Optional[typing.Sequence[str]]
- Product root edge filter. Only return supply chains that start with an edge that has 1+ of the specified HS codes.
-
- not_product : typing.Optional[typing.Sequence[str]]
- Product root edge filter. Only return supply chains that start with an edge that has none of the specified HS codes.
-
component : typing.Optional[typing.Sequence[str]]
Component edge filter. Only return supply chains that contain at least one edge with 1+ of the specified HS codes.
@@ -2752,17 +2742,9 @@ async def project_entity_supply_chain_summary(
async def main() -> None:
await client.project_entity.project_entity_supply_chain_summary(
- project_id="Gam5qG",
- project_entity_id="GOeOE8",
- min_date="2023-03-15",
- product=["8536", "8544", "4016"],
- risk_factors=[
- "forced_labor_xinjiang_name",
- "forced_labor_xinjiang_uflpa",
- "forced_labor_uflpa_origin_direct",
- "exports_russian_gold",
- "export_to_sanctioned",
- ],
+ project_id="0n4473",
+ project_entity_id="yebNPJ",
+ max_depth=4,
)
@@ -2772,12 +2754,12 @@ async def main() -> None:
f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/supply_chain/upstream_summary",
method="GET",
params={
+ "product": product,
+ "-product": not_product,
"risk_factors": risk_factors,
"-risk_factors": not_risk,
"countries": countries,
"-countries": not_countries,
- "product": product,
- "-product": not_product,
"component": component,
"-component": not_component,
"min_date": min_date,
diff --git a/src/sayari/project_entity/types/__init__.py b/src/sayari/project_entity/types/__init__.py
index 250941d5..02a1fae0 100644
--- a/src/sayari/project_entity/types/__init__.py
+++ b/src/sayari/project_entity/types/__init__.py
@@ -4,14 +4,18 @@
from .attribute_type import AttributeType
from .attribute_types_response import AttributeTypesResponse
from .attribute_values import AttributeValues
+from .attributes_response import AttributesResponse
from .business_purpose import BusinessPurpose
from .case_status import CaseStatus
from .count_type import CountType
from .create_resolved_project_entity_request import CreateResolvedProjectEntityRequest
from .facet_bucket import FacetBucket
from .facets_response import FacetsResponse
+from .grouped_attribute import GroupedAttribute
+from .grouped_attribute_value import GroupedAttributeValue
from .location import Location
-from .match_result import MatchResult
+from .match_count import MatchCount
+from .match_profile_enum import MatchProfileEnum
from .match_strength_enum import MatchStrengthEnum
from .matched_attributes import MatchedAttributes
from .product_bucket import ProductBucket
@@ -25,6 +29,7 @@
from .project_entity_supply_chain_summary_response import ProjectEntitySupplyChainSummaryResponse
from .project_entity_supply_chain_summary_response_data import ProjectEntitySupplyChainSummaryResponseData
from .project_entity_supply_chain_upstream import ProjectEntitySupplyChainUpstream
+from .project_risk_category import ProjectRiskCategory
from .project_risk_factor import ProjectRiskFactor
from .resolution_attributes import ResolutionAttributes
from .resolution_profile import ResolutionProfile
@@ -48,14 +53,18 @@
"AttributeType",
"AttributeTypesResponse",
"AttributeValues",
+ "AttributesResponse",
"BusinessPurpose",
"CaseStatus",
"CountType",
"CreateResolvedProjectEntityRequest",
"FacetBucket",
"FacetsResponse",
+ "GroupedAttribute",
+ "GroupedAttributeValue",
"Location",
- "MatchResult",
+ "MatchCount",
+ "MatchProfileEnum",
"MatchStrengthEnum",
"MatchedAttributes",
"ProductBucket",
@@ -69,6 +78,7 @@
"ProjectEntitySupplyChainSummaryResponse",
"ProjectEntitySupplyChainSummaryResponseData",
"ProjectEntitySupplyChainUpstream",
+ "ProjectRiskCategory",
"ProjectRiskFactor",
"ResolutionAttributes",
"ResolutionProfile",
diff --git a/src/sayari/project/types/hs_code_agg.py b/src/sayari/project_entity/types/attributes_response.py
similarity index 78%
rename from src/sayari/project/types/hs_code_agg.py
rename to src/sayari/project_entity/types/attributes_response.py
index 6bd27b37..7a96e2d2 100644
--- a/src/sayari/project/types/hs_code_agg.py
+++ b/src/sayari/project_entity/types/attributes_response.py
@@ -1,15 +1,14 @@
# This file was auto-generated by Fern from our API Definition.
from ...core.pydantic_utilities import UniversalBaseModel
-from .hs_code_agg_terms import HsCodeAggTerms
-from ...core.pydantic_utilities import IS_PYDANTIC_V2
import typing
+from .grouped_attribute import GroupedAttribute
+from ...core.pydantic_utilities import IS_PYDANTIC_V2
import pydantic
-class HsCodeAgg(UniversalBaseModel):
- doc_count: int
- hs_code_terms: HsCodeAggTerms
+class AttributesResponse(UniversalBaseModel):
+ data: typing.List[GroupedAttribute]
if IS_PYDANTIC_V2:
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
diff --git a/src/sayari/project/types/hs_code_agg_terms.py b/src/sayari/project_entity/types/grouped_attribute.py
similarity index 71%
rename from src/sayari/project/types/hs_code_agg_terms.py
rename to src/sayari/project_entity/types/grouped_attribute.py
index 17694ead..1c8a5842 100644
--- a/src/sayari/project/types/hs_code_agg_terms.py
+++ b/src/sayari/project_entity/types/grouped_attribute.py
@@ -2,15 +2,15 @@
from ...core.pydantic_utilities import UniversalBaseModel
import typing
-from .hs_code_agg_bucket import HsCodeAggBucket
+from .grouped_attribute_value import GroupedAttributeValue
from ...core.pydantic_utilities import IS_PYDANTIC_V2
import pydantic
-class HsCodeAggTerms(UniversalBaseModel):
- doc_count_error_upper_bound: int
- sum_other_doc_count: int
- buckets: typing.List[HsCodeAggBucket]
+class GroupedAttribute(UniversalBaseModel):
+ field: str
+ match_resolution: bool
+ values: typing.List[GroupedAttributeValue]
if IS_PYDANTIC_V2:
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
diff --git a/src/sayari/project/types/hs_code_agg_bucket.py b/src/sayari/project_entity/types/grouped_attribute_value.py
similarity index 74%
rename from src/sayari/project/types/hs_code_agg_bucket.py
rename to src/sayari/project_entity/types/grouped_attribute_value.py
index e4df0e38..159d6b89 100644
--- a/src/sayari/project/types/hs_code_agg_bucket.py
+++ b/src/sayari/project_entity/types/grouped_attribute_value.py
@@ -1,16 +1,14 @@
# This file was auto-generated by Fern from our API Definition.
from ...core.pydantic_utilities import UniversalBaseModel
-import typing
-from .int_key_value import IntKeyValue
from ...core.pydantic_utilities import IS_PYDANTIC_V2
+import typing
import pydantic
-class HsCodeAggBucket(UniversalBaseModel):
- key: str
- doc_count: int
- hs_code_sums: typing.Optional[IntKeyValue] = None
+class GroupedAttributeValue(UniversalBaseModel):
+ id: str
+ value: str
if IS_PYDANTIC_V2:
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
diff --git a/src/sayari/project_entity/types/match_count.py b/src/sayari/project_entity/types/match_count.py
new file mode 100644
index 00000000..e87a8660
--- /dev/null
+++ b/src/sayari/project_entity/types/match_count.py
@@ -0,0 +1,5 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+MatchCount = typing.Union[typing.Literal["one", "many"], typing.Any]
diff --git a/src/sayari/project_entity/types/match_profile_enum.py b/src/sayari/project_entity/types/match_profile_enum.py
new file mode 100644
index 00000000..6a86c378
--- /dev/null
+++ b/src/sayari/project_entity/types/match_profile_enum.py
@@ -0,0 +1,5 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+MatchProfileEnum = typing.Union[typing.Literal["corporate", "suppliers", "screen", "search"], typing.Any]
diff --git a/src/sayari/project_entity/types/match_result.py b/src/sayari/project_entity/types/match_result.py
deleted file mode 100644
index 2a9e1e8f..00000000
--- a/src/sayari/project_entity/types/match_result.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-MatchResult = typing.Union[typing.Literal["ambiguous", "unambiguous", "unresolved", "sayari"], typing.Any]
diff --git a/src/sayari/project_entity/types/project_entities_response.py b/src/sayari/project_entity/types/project_entities_response.py
index 83e03c86..abbcc145 100644
--- a/src/sayari/project_entity/types/project_entities_response.py
+++ b/src/sayari/project_entity/types/project_entities_response.py
@@ -21,6 +21,7 @@ class ProjectEntitiesResponse(UniversalBaseModel):
ProjectEntitiesResponse,
ProjectEntityMatchResponse,
ProjectEntityResponse,
+ ProjectRiskCategory,
ProjectRiskFactor,
SourceField,
TradeCounts,
@@ -55,6 +56,89 @@ class ProjectEntitiesResponse(UniversalBaseModel):
values=["253400V1H6ART1UQ0N98"],
),
},
+ countries=[
+ "USA",
+ "CYP",
+ "ITA",
+ "CHN",
+ "RUS",
+ "UKR",
+ "IND",
+ "IRL",
+ "KAZ",
+ "DEU",
+ ],
+ risk_categories=[
+ ProjectRiskCategory(
+ id="regulatory_action",
+ label="Regulatory action",
+ risk_factors=["regulatory_action"],
+ ),
+ ProjectRiskCategory(
+ id="export_controls",
+ label="Export controls",
+ risk_factors=["meu_list_contractors", "export_controls"],
+ ),
+ ProjectRiskCategory(
+ id="political_exposure",
+ label="Political exposure",
+ risk_factors=["soe_adjacent", "pep_adjacent"],
+ ),
+ ProjectRiskCategory(
+ id="sanctions",
+ label="Sanctions",
+ risk_factors=["sanctioned", "formerly_sanctioned"],
+ ),
+ ProjectRiskCategory(
+ id="adverse_media",
+ label="Adverse media",
+ risk_factors=["reputational_risk_other"],
+ ),
+ ],
+ risk_factors=[
+ ProjectRiskFactor(
+ id="regulatory_action",
+ ),
+ ProjectRiskFactor(
+ id="sanctioned",
+ ),
+ ProjectRiskFactor(
+ id="meu_list_contractors",
+ ),
+ ProjectRiskFactor(
+ id="reputational_risk_other",
+ ),
+ ProjectRiskFactor(
+ id="pep_adjacent",
+ ),
+ ProjectRiskFactor(
+ id="state_owned",
+ ),
+ ProjectRiskFactor(
+ id="export_controls",
+ ),
+ ProjectRiskFactor(
+ id="formerly_sanctioned",
+ ),
+ ProjectRiskFactor(
+ id="basel_aml",
+ ),
+ ProjectRiskFactor(
+ id="cpi_score",
+ ),
+ ],
+ upstream=UpstreamInfo(
+ risk_factors=[],
+ countries=[],
+ trade_counts=TradeCounts(
+ shipper_of=56,
+ receiver_of=2,
+ ),
+ has_upstream=False,
+ products=[],
+ ),
+ tags=[],
+ case="not_assigned",
matches=[
ProjectEntityMatchResponse(
match_id="52z4Wa:dy-rh2g0QtzUN_jC_e9S_A",
@@ -94,6 +178,36 @@ class ProjectEntitiesResponse(UniversalBaseModel):
"KAZ",
"DEU",
],
+ risk_categories=[
+ ProjectRiskCategory(
+ id="regulatory_action",
+ label="Regulatory action",
+ risk_factors=["regulatory_action"],
+ ),
+ ProjectRiskCategory(
+ id="export_controls",
+ label="Export controls",
+ risk_factors=[
+ "meu_list_contractors",
+ "export_controls",
+ ],
+ ),
+ ProjectRiskCategory(
+ id="political_exposure",
+ label="Political exposure",
+ risk_factors=["soe_adjacent", "pep_adjacent"],
+ ),
+ ProjectRiskCategory(
+ id="sanctions",
+ label="Sanctions",
+ risk_factors=["sanctioned", "formerly_sanctioned"],
+ ),
+ ProjectRiskCategory(
+ id="adverse_media",
+ label="Adverse media",
+ risk_factors=["reputational_risk_other"],
+ ),
+ ],
risk_factors=[
ProjectRiskFactor(
id="regulatory_action",
@@ -366,8 +480,6 @@ class ProjectEntitiesResponse(UniversalBaseModel):
updated_at="2025-04-22 22:54:00.913586+00",
)
],
- tags=[],
- case="not_assigned",
)
],
size=QualifiedCount(
diff --git a/src/sayari/project_entity/types/project_entity_match_response.py b/src/sayari/project_entity/types/project_entity_match_response.py
index a3cbbbac..2fab5108 100644
--- a/src/sayari/project_entity/types/project_entity_match_response.py
+++ b/src/sayari/project_entity/types/project_entity_match_response.py
@@ -3,11 +3,13 @@
from ...core.pydantic_utilities import UniversalBaseModel
from .matched_attributes import MatchedAttributes
import typing
+from .project_risk_category import ProjectRiskCategory
from .project_risk_factor import ProjectRiskFactor
from .business_purpose import BusinessPurpose
from .upstream_info import UpstreamInfo
from .source_field import SourceField
from .address import Address
+from .match_profile_enum import MatchProfileEnum
from ...core.pydantic_utilities import IS_PYDANTIC_V2
import pydantic
@@ -19,6 +21,7 @@ class ProjectEntityMatchResponse(UniversalBaseModel):
label: str
matched_attributes: MatchedAttributes
countries: typing.List[str]
+ risk_categories: typing.List[ProjectRiskCategory]
risk_factors: typing.List[ProjectRiskFactor]
business_purpose: typing.List[BusinessPurpose]
upstream: UpstreamInfo
@@ -27,7 +30,7 @@ class ProjectEntityMatchResponse(UniversalBaseModel):
hs_codes: typing.List[str]
created_at: str
updated_at: typing.Optional[str] = None
- resolution_profile: typing.Optional[str] = None
+ match_profile: typing.Optional[MatchProfileEnum] = None
deleted_at: typing.Optional[str] = None
if IS_PYDANTIC_V2:
diff --git a/src/sayari/project_entity/types/project_entity_response.py b/src/sayari/project_entity/types/project_entity_response.py
index 4e205781..11b7dcc5 100644
--- a/src/sayari/project_entity/types/project_entity_response.py
+++ b/src/sayari/project_entity/types/project_entity_response.py
@@ -4,10 +4,12 @@
import typing
from .match_strength_enum import MatchStrengthEnum
from .attribute_values import AttributeValues
-from .product_mapping import ProductMapping
-from .project_entity_match_response import ProjectEntityMatchResponse
+from .project_risk_category import ProjectRiskCategory
+from .project_risk_factor import ProjectRiskFactor
+from .upstream_info import UpstreamInfo
from .tag_response import TagResponse
from .case_status import CaseStatus
+from .project_entity_match_response import ProjectEntityMatchResponse
from ...core.pydantic_utilities import IS_PYDANTIC_V2
import pydantic
@@ -20,10 +22,13 @@ class ProjectEntityResponse(UniversalBaseModel):
strength: MatchStrengthEnum
created_at: str
attributes: typing.Dict[str, AttributeValues]
- product_mapping: typing.Optional[ProductMapping] = None
- matches: typing.List[ProjectEntityMatchResponse]
+ countries: typing.List[str]
+ risk_categories: typing.List[ProjectRiskCategory]
+ risk_factors: typing.List[ProjectRiskFactor]
+ upstream: UpstreamInfo
tags: typing.List[TagResponse]
case: typing.Optional[CaseStatus] = None
+ matches: typing.List[ProjectEntityMatchResponse]
updated_at: typing.Optional[str] = None
if IS_PYDANTIC_V2:
diff --git a/src/sayari/project_entity/types/project_risk_category.py b/src/sayari/project_entity/types/project_risk_category.py
new file mode 100644
index 00000000..eb159c52
--- /dev/null
+++ b/src/sayari/project_entity/types/project_risk_category.py
@@ -0,0 +1,21 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from ...core.pydantic_utilities import UniversalBaseModel
+import typing
+from ...core.pydantic_utilities import IS_PYDANTIC_V2
+import pydantic
+
+
+class ProjectRiskCategory(UniversalBaseModel):
+ id: str
+ label: str
+ risk_factors: typing.List[str]
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/sayari/project_entity/types/single_project_entity_response.py b/src/sayari/project_entity/types/single_project_entity_response.py
index 6724c644..f8319bb0 100644
--- a/src/sayari/project_entity/types/single_project_entity_response.py
+++ b/src/sayari/project_entity/types/single_project_entity_response.py
@@ -16,9 +16,9 @@ class SingleProjectEntityResponse(UniversalBaseModel):
AttributeValues,
BusinessPurpose,
MatchedAttributes,
- ProductMapping,
ProjectEntityMatchResponse,
ProjectEntityResponse,
+ ProjectRiskCategory,
ProjectRiskFactor,
SingleProjectEntityResponse,
SourceField,
@@ -52,10 +52,89 @@ class SingleProjectEntityResponse(UniversalBaseModel):
values=["253400V1H6ART1UQ0N98"],
),
},
- product_mapping=ProductMapping(
- state="unmapped",
+ countries=[
+ "USA",
+ "CYP",
+ "ITA",
+ "CHN",
+ "RUS",
+ "UKR",
+ "IND",
+ "IRL",
+ "KAZ",
+ "DEU",
+ ],
+ risk_categories=[
+ ProjectRiskCategory(
+ id="regulatory_action",
+ label="Regulatory action",
+ risk_factors=["regulatory_action"],
+ ),
+ ProjectRiskCategory(
+ id="export_controls",
+ label="Export controls",
+ risk_factors=["meu_list_contractors", "export_controls"],
+ ),
+ ProjectRiskCategory(
+ id="political_exposure",
+ label="Political exposure",
+ risk_factors=["soe_adjacent", "pep_adjacent"],
+ ),
+ ProjectRiskCategory(
+ id="sanctions",
+ label="Sanctions",
+ risk_factors=["sanctioned", "formerly_sanctioned"],
+ ),
+ ProjectRiskCategory(
+ id="adverse_media",
+ label="Adverse media",
+ risk_factors=["reputational_risk_other"],
+ ),
+ ],
+ risk_factors=[
+ ProjectRiskFactor(
+ id="regulatory_action",
+ ),
+ ProjectRiskFactor(
+ id="sanctioned",
+ ),
+ ProjectRiskFactor(
+ id="meu_list_contractors",
+ ),
+ ProjectRiskFactor(
+ id="reputational_risk_other",
+ ),
+ ProjectRiskFactor(
+ id="pep_adjacent",
+ ),
+ ProjectRiskFactor(
+ id="state_owned",
+ ),
+ ProjectRiskFactor(
+ id="export_controls",
+ ),
+ ProjectRiskFactor(
+ id="formerly_sanctioned",
+ ),
+ ProjectRiskFactor(
+ id="basel_aml",
+ ),
+ ProjectRiskFactor(
+ id="cpi_score",
+ ),
+ ],
+ upstream=UpstreamInfo(
+ risk_factors=[],
+ countries=[],
+ trade_counts=TradeCounts(
+ shipper_of=56,
+ receiver_of=2,
+ ),
+ has_upstream=False,
products=[],
),
+ tags=[],
+ case="not_assigned",
matches=[
ProjectEntityMatchResponse(
match_id="52z4Wa:dy-rh2g0QtzUN_jC_e9S_A",
@@ -95,6 +174,36 @@ class SingleProjectEntityResponse(UniversalBaseModel):
"KAZ",
"DEU",
],
+ risk_categories=[
+ ProjectRiskCategory(
+ id="regulatory_action",
+ label="Regulatory action",
+ risk_factors=["regulatory_action"],
+ ),
+ ProjectRiskCategory(
+ id="export_controls",
+ label="Export controls",
+ risk_factors=[
+ "meu_list_contractors",
+ "export_controls",
+ ],
+ ),
+ ProjectRiskCategory(
+ id="political_exposure",
+ label="Political exposure",
+ risk_factors=["soe_adjacent", "pep_adjacent"],
+ ),
+ ProjectRiskCategory(
+ id="sanctions",
+ label="Sanctions",
+ risk_factors=["sanctioned", "formerly_sanctioned"],
+ ),
+ ProjectRiskCategory(
+ id="adverse_media",
+ label="Adverse media",
+ risk_factors=["reputational_risk_other"],
+ ),
+ ],
risk_factors=[
ProjectRiskFactor(
id="regulatory_action",
@@ -369,8 +478,6 @@ class SingleProjectEntityResponse(UniversalBaseModel):
updated_at="2025-04-22 22:54:00.913586+00",
)
],
- tags=[],
- case="not_assigned",
),
)
"""
diff --git a/src/sayari/project_entity_attributes/__init__.py b/src/sayari/project_entity_attributes/__init__.py
new file mode 100644
index 00000000..7ba8a944
--- /dev/null
+++ b/src/sayari/project_entity_attributes/__init__.py
@@ -0,0 +1,13 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from .types import (
+ UpdateProjectEntityAttributeRequest,
+ UpdateProjectEntityAttributeResponse,
+ UpdateProjectEntityAttributeResponseData,
+)
+
+__all__ = [
+ "UpdateProjectEntityAttributeRequest",
+ "UpdateProjectEntityAttributeResponse",
+ "UpdateProjectEntityAttributeResponseData",
+]
diff --git a/src/sayari/project_entity_attributes/client.py b/src/sayari/project_entity_attributes/client.py
new file mode 100644
index 00000000..7bb2d741
--- /dev/null
+++ b/src/sayari/project_entity_attributes/client.py
@@ -0,0 +1,310 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from ..core.client_wrapper import SyncClientWrapper
+from .types.update_project_entity_attribute_request import UpdateProjectEntityAttributeRequest
+from ..core.request_options import RequestOptions
+from .types.update_project_entity_attribute_response import UpdateProjectEntityAttributeResponse
+from ..core.jsonable_encoder import jsonable_encoder
+from ..core.serialization import convert_and_respect_annotation_metadata
+from ..core.pydantic_utilities import parse_obj_as
+from ..shared_errors.errors.bad_request import BadRequest
+from ..shared_errors.types.bad_request_response import BadRequestResponse
+from ..shared_errors.errors.unauthorized import Unauthorized
+from ..shared_errors.types.unauthorized_response import UnauthorizedResponse
+from ..shared_errors.errors.not_found import NotFound
+from ..shared_errors.types.not_found_response import NotFoundResponse
+from ..shared_errors.errors.method_not_allowed import MethodNotAllowed
+from ..shared_errors.types.method_not_allowed_response import MethodNotAllowedResponse
+from ..shared_errors.errors.rate_limit_exceeded import RateLimitExceeded
+from ..shared_errors.types.rate_limit_response import RateLimitResponse
+from ..shared_errors.errors.internal_server_error import InternalServerError
+from ..shared_errors.types.internal_server_error_response import InternalServerErrorResponse
+from json.decoder import JSONDecodeError
+from ..core.api_error import ApiError
+from ..core.client_wrapper import AsyncClientWrapper
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class ProjectEntityAttributesClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def update_project_entity_attribute(
+ self,
+ project_id: str,
+ project_entity_id: str,
+ attribute_id: str,
+ *,
+ request: UpdateProjectEntityAttributeRequest,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> UpdateProjectEntityAttributeResponse:
+ """
+ Updates a specific attribute for a project entity.
+
+ Parameters
+ ----------
+ project_id : str
+
+ project_entity_id : str
+
+ attribute_id : str
+
+ request : UpdateProjectEntityAttributeRequest
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ UpdateProjectEntityAttributeResponse
+
+ Examples
+ --------
+ from sayari import Sayari
+ from sayari.project_entity_attributes import UpdateProjectEntityAttributeRequest
+
+ client = Sayari(
+ client_id="YOUR_CLIENT_ID",
+ client_secret="YOUR_CLIENT_SECRET",
+ )
+ client.project_entity_attributes.update_project_entity_attribute(
+ project_id="V03eYM",
+ project_entity_id="BG72YW",
+ attribute_id="xG8wYP",
+ request=UpdateProjectEntityAttributeRequest(
+ field="name",
+ value="updated name",
+ match_resolution=True,
+ ),
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/attributes/{jsonable_encoder(attribute_id)}",
+ method="PUT",
+ json=convert_and_respect_annotation_metadata(
+ object_=request, annotation=UpdateProjectEntityAttributeRequest, direction="write"
+ ),
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return typing.cast(
+ UpdateProjectEntityAttributeResponse,
+ parse_obj_as(
+ type_=UpdateProjectEntityAttributeResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ if _response.status_code == 400:
+ raise BadRequest(
+ typing.cast(
+ BadRequestResponse,
+ parse_obj_as(
+ type_=BadRequestResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 401:
+ raise Unauthorized(
+ typing.cast(
+ UnauthorizedResponse,
+ parse_obj_as(
+ type_=UnauthorizedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 404:
+ raise NotFound(
+ typing.cast(
+ NotFoundResponse,
+ parse_obj_as(
+ type_=NotFoundResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 405:
+ raise MethodNotAllowed(
+ typing.cast(
+ MethodNotAllowedResponse,
+ parse_obj_as(
+ type_=MethodNotAllowedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 429:
+ raise RateLimitExceeded(
+ typing.cast(
+ RateLimitResponse,
+ parse_obj_as(
+ type_=RateLimitResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ typing.cast(
+ InternalServerErrorResponse,
+ parse_obj_as(
+ type_=InternalServerErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+
+class AsyncProjectEntityAttributesClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def update_project_entity_attribute(
+ self,
+ project_id: str,
+ project_entity_id: str,
+ attribute_id: str,
+ *,
+ request: UpdateProjectEntityAttributeRequest,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> UpdateProjectEntityAttributeResponse:
+ """
+ Updates a specific attribute for a project entity.
+
+ Parameters
+ ----------
+ project_id : str
+
+ project_entity_id : str
+
+ attribute_id : str
+
+ request : UpdateProjectEntityAttributeRequest
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ UpdateProjectEntityAttributeResponse
+
+ Examples
+ --------
+ import asyncio
+
+ from sayari import AsyncSayari
+ from sayari.project_entity_attributes import UpdateProjectEntityAttributeRequest
+
+ client = AsyncSayari(
+ client_id="YOUR_CLIENT_ID",
+ client_secret="YOUR_CLIENT_SECRET",
+ )
+
+
+ async def main() -> None:
+ await client.project_entity_attributes.update_project_entity_attribute(
+ project_id="V03eYM",
+ project_entity_id="BG72YW",
+ attribute_id="xG8wYP",
+ request=UpdateProjectEntityAttributeRequest(
+ field="name",
+ value="updated name",
+ match_resolution=True,
+ ),
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/attributes/{jsonable_encoder(attribute_id)}",
+ method="PUT",
+ json=convert_and_respect_annotation_metadata(
+ object_=request, annotation=UpdateProjectEntityAttributeRequest, direction="write"
+ ),
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return typing.cast(
+ UpdateProjectEntityAttributeResponse,
+ parse_obj_as(
+ type_=UpdateProjectEntityAttributeResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ if _response.status_code == 400:
+ raise BadRequest(
+ typing.cast(
+ BadRequestResponse,
+ parse_obj_as(
+ type_=BadRequestResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 401:
+ raise Unauthorized(
+ typing.cast(
+ UnauthorizedResponse,
+ parse_obj_as(
+ type_=UnauthorizedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 404:
+ raise NotFound(
+ typing.cast(
+ NotFoundResponse,
+ parse_obj_as(
+ type_=NotFoundResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 405:
+ raise MethodNotAllowed(
+ typing.cast(
+ MethodNotAllowedResponse,
+ parse_obj_as(
+ type_=MethodNotAllowedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 429:
+ raise RateLimitExceeded(
+ typing.cast(
+ RateLimitResponse,
+ parse_obj_as(
+ type_=RateLimitResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ typing.cast(
+ InternalServerErrorResponse,
+ parse_obj_as(
+ type_=InternalServerErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
diff --git a/src/sayari/project_entity_attributes/types/__init__.py b/src/sayari/project_entity_attributes/types/__init__.py
new file mode 100644
index 00000000..d9b20917
--- /dev/null
+++ b/src/sayari/project_entity_attributes/types/__init__.py
@@ -0,0 +1,11 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from .update_project_entity_attribute_request import UpdateProjectEntityAttributeRequest
+from .update_project_entity_attribute_response import UpdateProjectEntityAttributeResponse
+from .update_project_entity_attribute_response_data import UpdateProjectEntityAttributeResponseData
+
+__all__ = [
+ "UpdateProjectEntityAttributeRequest",
+ "UpdateProjectEntityAttributeResponse",
+ "UpdateProjectEntityAttributeResponseData",
+]
diff --git a/src/sayari/project_entity_attributes/types/update_project_entity_attribute_request.py b/src/sayari/project_entity_attributes/types/update_project_entity_attribute_request.py
new file mode 100644
index 00000000..845fc91f
--- /dev/null
+++ b/src/sayari/project_entity_attributes/types/update_project_entity_attribute_request.py
@@ -0,0 +1,33 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from ...core.pydantic_utilities import UniversalBaseModel
+from ...core.pydantic_utilities import IS_PYDANTIC_V2
+import typing
+import pydantic
+
+
+class UpdateProjectEntityAttributeRequest(UniversalBaseModel):
+ """
+ Examples
+ --------
+ from sayari.project_entity_attributes import UpdateProjectEntityAttributeRequest
+
+ UpdateProjectEntityAttributeRequest(
+ field="name",
+ value="updated name",
+ match_resolution=True,
+ )
+ """
+
+ field: str
+ value: str
+ match_resolution: bool
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/sayari/project_entity_attributes/types/update_project_entity_attribute_response.py b/src/sayari/project_entity_attributes/types/update_project_entity_attribute_response.py
new file mode 100644
index 00000000..62c230a3
--- /dev/null
+++ b/src/sayari/project_entity_attributes/types/update_project_entity_attribute_response.py
@@ -0,0 +1,38 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from ...core.pydantic_utilities import UniversalBaseModel
+from .update_project_entity_attribute_response_data import UpdateProjectEntityAttributeResponseData
+from ...core.pydantic_utilities import IS_PYDANTIC_V2
+import typing
+import pydantic
+
+
+class UpdateProjectEntityAttributeResponse(UniversalBaseModel):
+ """
+ Examples
+ --------
+ from sayari.project_entity_attributes import (
+ UpdateProjectEntityAttributeResponse,
+ UpdateProjectEntityAttributeResponseData,
+ )
+
+ UpdateProjectEntityAttributeResponse(
+ data=UpdateProjectEntityAttributeResponseData(
+ id="xG8wYP",
+ field="name",
+ value="updated name",
+ match_resolution=True,
+ ),
+ )
+ """
+
+ data: UpdateProjectEntityAttributeResponseData
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/sayari/project_entity_attributes/types/update_project_entity_attribute_response_data.py b/src/sayari/project_entity_attributes/types/update_project_entity_attribute_response_data.py
new file mode 100644
index 00000000..f1acceed
--- /dev/null
+++ b/src/sayari/project_entity_attributes/types/update_project_entity_attribute_response_data.py
@@ -0,0 +1,22 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from ...core.pydantic_utilities import UniversalBaseModel
+from ...core.pydantic_utilities import IS_PYDANTIC_V2
+import typing
+import pydantic
+
+
+class UpdateProjectEntityAttributeResponseData(UniversalBaseModel):
+ id: str
+ field: str
+ value: str
+ match_resolution: bool
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/sayari/project_entity_supply_chain_snapshots/__init__.py b/src/sayari/project_entity_supply_chain_snapshots/__init__.py
new file mode 100644
index 00000000..b86fce6e
--- /dev/null
+++ b/src/sayari/project_entity_supply_chain_snapshots/__init__.py
@@ -0,0 +1,23 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from .types import (
+ CreateProjectEntitySupplyChainSnapshotRequest,
+ CreateProjectEntitySupplyChainSnapshotResponse,
+ ProjectEntitySupplyChainSnapshotByIdResponse,
+ ProjectEntitySupplyChainSnapshotData,
+ ProjectEntitySupplyChainSnapshotDetailData,
+ ProjectEntitySupplyChainSnapshotsResponse,
+ SupplyChainEdge,
+ SupplyChainNode,
+)
+
+__all__ = [
+ "CreateProjectEntitySupplyChainSnapshotRequest",
+ "CreateProjectEntitySupplyChainSnapshotResponse",
+ "ProjectEntitySupplyChainSnapshotByIdResponse",
+ "ProjectEntitySupplyChainSnapshotData",
+ "ProjectEntitySupplyChainSnapshotDetailData",
+ "ProjectEntitySupplyChainSnapshotsResponse",
+ "SupplyChainEdge",
+ "SupplyChainNode",
+]
diff --git a/src/sayari/project_entity_supply_chain_snapshots/client.py b/src/sayari/project_entity_supply_chain_snapshots/client.py
new file mode 100644
index 00000000..3b2c7258
--- /dev/null
+++ b/src/sayari/project_entity_supply_chain_snapshots/client.py
@@ -0,0 +1,1014 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+from ..core.client_wrapper import SyncClientWrapper
+from ..core.request_options import RequestOptions
+from .types.project_entity_supply_chain_snapshots_response import ProjectEntitySupplyChainSnapshotsResponse
+from ..core.jsonable_encoder import jsonable_encoder
+from ..core.pydantic_utilities import parse_obj_as
+from ..shared_errors.errors.bad_request import BadRequest
+from ..shared_errors.types.bad_request_response import BadRequestResponse
+from ..shared_errors.errors.unauthorized import Unauthorized
+from ..shared_errors.types.unauthorized_response import UnauthorizedResponse
+from ..shared_errors.errors.not_found import NotFound
+from ..shared_errors.types.not_found_response import NotFoundResponse
+from ..shared_errors.errors.method_not_allowed import MethodNotAllowed
+from ..shared_errors.types.method_not_allowed_response import MethodNotAllowedResponse
+from ..shared_errors.errors.rate_limit_exceeded import RateLimitExceeded
+from ..shared_errors.types.rate_limit_response import RateLimitResponse
+from ..shared_errors.errors.internal_server_error import InternalServerError
+from ..shared_errors.types.internal_server_error_response import InternalServerErrorResponse
+from json.decoder import JSONDecodeError
+from ..core.api_error import ApiError
+from .types.project_entity_supply_chain_snapshot_by_id_response import ProjectEntitySupplyChainSnapshotByIdResponse
+from .types.create_project_entity_supply_chain_snapshot_request import CreateProjectEntitySupplyChainSnapshotRequest
+from .types.create_project_entity_supply_chain_snapshot_response import CreateProjectEntitySupplyChainSnapshotResponse
+from ..core.serialization import convert_and_respect_annotation_metadata
+from ..core.client_wrapper import AsyncClientWrapper
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class ProjectEntitySupplyChainSnapshotsClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ def get_project_entity_supply_chain_snapshots(
+ self, project_id: str, project_entity_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> ProjectEntitySupplyChainSnapshotsResponse:
+ """
+ Retrieves all supply chain snapshots for a project entity.
+
+ Parameters
+ ----------
+ project_id : str
+
+ project_entity_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ProjectEntitySupplyChainSnapshotsResponse
+
+ Examples
+ --------
+ from sayari import Sayari
+
+ client = Sayari(
+ client_id="YOUR_CLIENT_ID",
+ client_secret="YOUR_CLIENT_SECRET",
+ )
+ client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_snapshots(
+ project_id="V03eYM",
+ project_entity_id="BG72YW",
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/supply_chain/snapshots",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return typing.cast(
+ ProjectEntitySupplyChainSnapshotsResponse,
+ parse_obj_as(
+ type_=ProjectEntitySupplyChainSnapshotsResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ if _response.status_code == 400:
+ raise BadRequest(
+ typing.cast(
+ BadRequestResponse,
+ parse_obj_as(
+ type_=BadRequestResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 401:
+ raise Unauthorized(
+ typing.cast(
+ UnauthorizedResponse,
+ parse_obj_as(
+ type_=UnauthorizedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 404:
+ raise NotFound(
+ typing.cast(
+ NotFoundResponse,
+ parse_obj_as(
+ type_=NotFoundResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 405:
+ raise MethodNotAllowed(
+ typing.cast(
+ MethodNotAllowedResponse,
+ parse_obj_as(
+ type_=MethodNotAllowedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 429:
+ raise RateLimitExceeded(
+ typing.cast(
+ RateLimitResponse,
+ parse_obj_as(
+ type_=RateLimitResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ typing.cast(
+ InternalServerErrorResponse,
+ parse_obj_as(
+ type_=InternalServerErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def get_project_entity_supply_chain_snapshot_by_id(
+ self,
+ project_id: str,
+ project_entity_id: str,
+ snapshot_id: str,
+ *,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ProjectEntitySupplyChainSnapshotByIdResponse:
+ """
+ Retrieves a specific supply chain snapshot by ID for a project entity.
+
+ Parameters
+ ----------
+ project_id : str
+
+ project_entity_id : str
+
+ snapshot_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ProjectEntitySupplyChainSnapshotByIdResponse
+
+ Examples
+ --------
+ from sayari import Sayari
+
+ client = Sayari(
+ client_id="YOUR_CLIENT_ID",
+ client_secret="YOUR_CLIENT_SECRET",
+ )
+ client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_snapshot_by_id(
+ project_id="V03eYM",
+ project_entity_id="BG72YW",
+ snapshot_id="sN4p2K",
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/supply_chain/snapshots/{jsonable_encoder(snapshot_id)}",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return typing.cast(
+ ProjectEntitySupplyChainSnapshotByIdResponse,
+ parse_obj_as(
+ type_=ProjectEntitySupplyChainSnapshotByIdResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ if _response.status_code == 400:
+ raise BadRequest(
+ typing.cast(
+ BadRequestResponse,
+ parse_obj_as(
+ type_=BadRequestResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 401:
+ raise Unauthorized(
+ typing.cast(
+ UnauthorizedResponse,
+ parse_obj_as(
+ type_=UnauthorizedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 404:
+ raise NotFound(
+ typing.cast(
+ NotFoundResponse,
+ parse_obj_as(
+ type_=NotFoundResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 405:
+ raise MethodNotAllowed(
+ typing.cast(
+ MethodNotAllowedResponse,
+ parse_obj_as(
+ type_=MethodNotAllowedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 429:
+ raise RateLimitExceeded(
+ typing.cast(
+ RateLimitResponse,
+ parse_obj_as(
+ type_=RateLimitResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ typing.cast(
+ InternalServerErrorResponse,
+ parse_obj_as(
+ type_=InternalServerErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def create_project_entity_supply_chain_snapshot(
+ self,
+ project_id: str,
+ project_entity_id: str,
+ *,
+ request: CreateProjectEntitySupplyChainSnapshotRequest,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> CreateProjectEntitySupplyChainSnapshotResponse:
+ """
+ Creates a new supply chain snapshot for a project entity.
+
+ Parameters
+ ----------
+ project_id : str
+
+ project_entity_id : str
+
+ request : CreateProjectEntitySupplyChainSnapshotRequest
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ CreateProjectEntitySupplyChainSnapshotResponse
+
+ Examples
+ --------
+ from sayari import Sayari
+ from sayari.project_entity_supply_chain_snapshots import (
+ CreateProjectEntitySupplyChainSnapshotRequest,
+ )
+
+ client = Sayari(
+ client_id="YOUR_CLIENT_ID",
+ client_secret="YOUR_CLIENT_SECRET",
+ )
+ client.project_entity_supply_chain_snapshots.create_project_entity_supply_chain_snapshot(
+ project_id="V03eYM",
+ project_entity_id="BG72YW",
+ request=CreateProjectEntitySupplyChainSnapshotRequest(
+ label="Q1 2024 Supply Chain Analysis",
+ ),
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/supply_chain/snapshots",
+ method="POST",
+ json=convert_and_respect_annotation_metadata(
+ object_=request, annotation=CreateProjectEntitySupplyChainSnapshotRequest, direction="write"
+ ),
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return typing.cast(
+ CreateProjectEntitySupplyChainSnapshotResponse,
+ parse_obj_as(
+ type_=CreateProjectEntitySupplyChainSnapshotResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ if _response.status_code == 400:
+ raise BadRequest(
+ typing.cast(
+ BadRequestResponse,
+ parse_obj_as(
+ type_=BadRequestResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 401:
+ raise Unauthorized(
+ typing.cast(
+ UnauthorizedResponse,
+ parse_obj_as(
+ type_=UnauthorizedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 404:
+ raise NotFound(
+ typing.cast(
+ NotFoundResponse,
+ parse_obj_as(
+ type_=NotFoundResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 405:
+ raise MethodNotAllowed(
+ typing.cast(
+ MethodNotAllowedResponse,
+ parse_obj_as(
+ type_=MethodNotAllowedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 429:
+ raise RateLimitExceeded(
+ typing.cast(
+ RateLimitResponse,
+ parse_obj_as(
+ type_=RateLimitResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ typing.cast(
+ InternalServerErrorResponse,
+ parse_obj_as(
+ type_=InternalServerErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ def delete_project_entity_supply_chain_snapshot_by_id(
+ self,
+ project_id: str,
+ project_entity_id: str,
+ snapshot_id: str,
+ *,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> None:
+ """
+ Deletes a specific supply chain snapshot by ID for a project entity.
+
+ Parameters
+ ----------
+ project_id : str
+
+ project_entity_id : str
+
+ snapshot_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ from sayari import Sayari
+
+ client = Sayari(
+ client_id="YOUR_CLIENT_ID",
+ client_secret="YOUR_CLIENT_SECRET",
+ )
+ client.project_entity_supply_chain_snapshots.delete_project_entity_supply_chain_snapshot_by_id(
+ project_id="project_id",
+ project_entity_id="project_entity_id",
+ snapshot_id="snapshot_id",
+ )
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/supply_chain/snapshots/{jsonable_encoder(snapshot_id)}",
+ method="DELETE",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return
+ if _response.status_code == 400:
+ raise BadRequest(
+ typing.cast(
+ BadRequestResponse,
+ parse_obj_as(
+ type_=BadRequestResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 401:
+ raise Unauthorized(
+ typing.cast(
+ UnauthorizedResponse,
+ parse_obj_as(
+ type_=UnauthorizedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 404:
+ raise NotFound(
+ typing.cast(
+ NotFoundResponse,
+ parse_obj_as(
+ type_=NotFoundResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 405:
+ raise MethodNotAllowed(
+ typing.cast(
+ MethodNotAllowedResponse,
+ parse_obj_as(
+ type_=MethodNotAllowedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 429:
+ raise RateLimitExceeded(
+ typing.cast(
+ RateLimitResponse,
+ parse_obj_as(
+ type_=RateLimitResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ typing.cast(
+ InternalServerErrorResponse,
+ parse_obj_as(
+ type_=InternalServerErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+
+class AsyncProjectEntitySupplyChainSnapshotsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def get_project_entity_supply_chain_snapshots(
+ self, project_id: str, project_entity_id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> ProjectEntitySupplyChainSnapshotsResponse:
+ """
+ Retrieves all supply chain snapshots for a project entity.
+
+ Parameters
+ ----------
+ project_id : str
+
+ project_entity_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ProjectEntitySupplyChainSnapshotsResponse
+
+ Examples
+ --------
+ import asyncio
+
+ from sayari import AsyncSayari
+
+ client = AsyncSayari(
+ client_id="YOUR_CLIENT_ID",
+ client_secret="YOUR_CLIENT_SECRET",
+ )
+
+
+ async def main() -> None:
+ await client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_snapshots(
+ project_id="V03eYM",
+ project_entity_id="BG72YW",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/supply_chain/snapshots",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return typing.cast(
+ ProjectEntitySupplyChainSnapshotsResponse,
+ parse_obj_as(
+ type_=ProjectEntitySupplyChainSnapshotsResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ if _response.status_code == 400:
+ raise BadRequest(
+ typing.cast(
+ BadRequestResponse,
+ parse_obj_as(
+ type_=BadRequestResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 401:
+ raise Unauthorized(
+ typing.cast(
+ UnauthorizedResponse,
+ parse_obj_as(
+ type_=UnauthorizedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 404:
+ raise NotFound(
+ typing.cast(
+ NotFoundResponse,
+ parse_obj_as(
+ type_=NotFoundResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 405:
+ raise MethodNotAllowed(
+ typing.cast(
+ MethodNotAllowedResponse,
+ parse_obj_as(
+ type_=MethodNotAllowedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 429:
+ raise RateLimitExceeded(
+ typing.cast(
+ RateLimitResponse,
+ parse_obj_as(
+ type_=RateLimitResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ typing.cast(
+ InternalServerErrorResponse,
+ parse_obj_as(
+ type_=InternalServerErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def get_project_entity_supply_chain_snapshot_by_id(
+ self,
+ project_id: str,
+ project_entity_id: str,
+ snapshot_id: str,
+ *,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ProjectEntitySupplyChainSnapshotByIdResponse:
+ """
+ Retrieves a specific supply chain snapshot by ID for a project entity.
+
+ Parameters
+ ----------
+ project_id : str
+
+ project_entity_id : str
+
+ snapshot_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ProjectEntitySupplyChainSnapshotByIdResponse
+
+ Examples
+ --------
+ import asyncio
+
+ from sayari import AsyncSayari
+
+ client = AsyncSayari(
+ client_id="YOUR_CLIENT_ID",
+ client_secret="YOUR_CLIENT_SECRET",
+ )
+
+
+ async def main() -> None:
+ await client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_snapshot_by_id(
+ project_id="V03eYM",
+ project_entity_id="BG72YW",
+ snapshot_id="sN4p2K",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/supply_chain/snapshots/{jsonable_encoder(snapshot_id)}",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return typing.cast(
+ ProjectEntitySupplyChainSnapshotByIdResponse,
+ parse_obj_as(
+ type_=ProjectEntitySupplyChainSnapshotByIdResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ if _response.status_code == 400:
+ raise BadRequest(
+ typing.cast(
+ BadRequestResponse,
+ parse_obj_as(
+ type_=BadRequestResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 401:
+ raise Unauthorized(
+ typing.cast(
+ UnauthorizedResponse,
+ parse_obj_as(
+ type_=UnauthorizedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 404:
+ raise NotFound(
+ typing.cast(
+ NotFoundResponse,
+ parse_obj_as(
+ type_=NotFoundResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 405:
+ raise MethodNotAllowed(
+ typing.cast(
+ MethodNotAllowedResponse,
+ parse_obj_as(
+ type_=MethodNotAllowedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 429:
+ raise RateLimitExceeded(
+ typing.cast(
+ RateLimitResponse,
+ parse_obj_as(
+ type_=RateLimitResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ typing.cast(
+ InternalServerErrorResponse,
+ parse_obj_as(
+ type_=InternalServerErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def create_project_entity_supply_chain_snapshot(
+ self,
+ project_id: str,
+ project_entity_id: str,
+ *,
+ request: CreateProjectEntitySupplyChainSnapshotRequest,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> CreateProjectEntitySupplyChainSnapshotResponse:
+ """
+ Creates a new supply chain snapshot for a project entity.
+
+ Parameters
+ ----------
+ project_id : str
+
+ project_entity_id : str
+
+ request : CreateProjectEntitySupplyChainSnapshotRequest
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ CreateProjectEntitySupplyChainSnapshotResponse
+
+ Examples
+ --------
+ import asyncio
+
+ from sayari import AsyncSayari
+ from sayari.project_entity_supply_chain_snapshots import (
+ CreateProjectEntitySupplyChainSnapshotRequest,
+ )
+
+ client = AsyncSayari(
+ client_id="YOUR_CLIENT_ID",
+ client_secret="YOUR_CLIENT_SECRET",
+ )
+
+
+ async def main() -> None:
+ await client.project_entity_supply_chain_snapshots.create_project_entity_supply_chain_snapshot(
+ project_id="V03eYM",
+ project_entity_id="BG72YW",
+ request=CreateProjectEntitySupplyChainSnapshotRequest(
+ label="Q1 2024 Supply Chain Analysis",
+ ),
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/supply_chain/snapshots",
+ method="POST",
+ json=convert_and_respect_annotation_metadata(
+ object_=request, annotation=CreateProjectEntitySupplyChainSnapshotRequest, direction="write"
+ ),
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return typing.cast(
+ CreateProjectEntitySupplyChainSnapshotResponse,
+ parse_obj_as(
+ type_=CreateProjectEntitySupplyChainSnapshotResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ if _response.status_code == 400:
+ raise BadRequest(
+ typing.cast(
+ BadRequestResponse,
+ parse_obj_as(
+ type_=BadRequestResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 401:
+ raise Unauthorized(
+ typing.cast(
+ UnauthorizedResponse,
+ parse_obj_as(
+ type_=UnauthorizedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 404:
+ raise NotFound(
+ typing.cast(
+ NotFoundResponse,
+ parse_obj_as(
+ type_=NotFoundResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 405:
+ raise MethodNotAllowed(
+ typing.cast(
+ MethodNotAllowedResponse,
+ parse_obj_as(
+ type_=MethodNotAllowedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 429:
+ raise RateLimitExceeded(
+ typing.cast(
+ RateLimitResponse,
+ parse_obj_as(
+ type_=RateLimitResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ typing.cast(
+ InternalServerErrorResponse,
+ parse_obj_as(
+ type_=InternalServerErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
+
+ async def delete_project_entity_supply_chain_snapshot_by_id(
+ self,
+ project_id: str,
+ project_entity_id: str,
+ snapshot_id: str,
+ *,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> None:
+ """
+ Deletes a specific supply chain snapshot by ID for a project entity.
+
+ Parameters
+ ----------
+ project_id : str
+
+ project_entity_id : str
+
+ snapshot_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ import asyncio
+
+ from sayari import AsyncSayari
+
+ client = AsyncSayari(
+ client_id="YOUR_CLIENT_ID",
+ client_secret="YOUR_CLIENT_SECRET",
+ )
+
+
+ async def main() -> None:
+ await client.project_entity_supply_chain_snapshots.delete_project_entity_supply_chain_snapshot_by_id(
+ project_id="project_id",
+ project_entity_id="project_entity_id",
+ snapshot_id="snapshot_id",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/supply_chain/snapshots/{jsonable_encoder(snapshot_id)}",
+ method="DELETE",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ return
+ if _response.status_code == 400:
+ raise BadRequest(
+ typing.cast(
+ BadRequestResponse,
+ parse_obj_as(
+ type_=BadRequestResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 401:
+ raise Unauthorized(
+ typing.cast(
+ UnauthorizedResponse,
+ parse_obj_as(
+ type_=UnauthorizedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 404:
+ raise NotFound(
+ typing.cast(
+ NotFoundResponse,
+ parse_obj_as(
+ type_=NotFoundResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 405:
+ raise MethodNotAllowed(
+ typing.cast(
+ MethodNotAllowedResponse,
+ parse_obj_as(
+ type_=MethodNotAllowedResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 429:
+ raise RateLimitExceeded(
+ typing.cast(
+ RateLimitResponse,
+ parse_obj_as(
+ type_=RateLimitResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ typing.cast(
+ InternalServerErrorResponse,
+ parse_obj_as(
+ type_=InternalServerErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, body=_response.text)
+ raise ApiError(status_code=_response.status_code, body=_response_json)
diff --git a/src/sayari/project_entity_supply_chain_snapshots/types/__init__.py b/src/sayari/project_entity_supply_chain_snapshots/types/__init__.py
new file mode 100644
index 00000000..bda52c12
--- /dev/null
+++ b/src/sayari/project_entity_supply_chain_snapshots/types/__init__.py
@@ -0,0 +1,21 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from .create_project_entity_supply_chain_snapshot_request import CreateProjectEntitySupplyChainSnapshotRequest
+from .create_project_entity_supply_chain_snapshot_response import CreateProjectEntitySupplyChainSnapshotResponse
+from .project_entity_supply_chain_snapshot_by_id_response import ProjectEntitySupplyChainSnapshotByIdResponse
+from .project_entity_supply_chain_snapshot_data import ProjectEntitySupplyChainSnapshotData
+from .project_entity_supply_chain_snapshot_detail_data import ProjectEntitySupplyChainSnapshotDetailData
+from .project_entity_supply_chain_snapshots_response import ProjectEntitySupplyChainSnapshotsResponse
+from .supply_chain_edge import SupplyChainEdge
+from .supply_chain_node import SupplyChainNode
+
+__all__ = [
+ "CreateProjectEntitySupplyChainSnapshotRequest",
+ "CreateProjectEntitySupplyChainSnapshotResponse",
+ "ProjectEntitySupplyChainSnapshotByIdResponse",
+ "ProjectEntitySupplyChainSnapshotData",
+ "ProjectEntitySupplyChainSnapshotDetailData",
+ "ProjectEntitySupplyChainSnapshotsResponse",
+ "SupplyChainEdge",
+ "SupplyChainNode",
+]
diff --git a/src/sayari/project_entity_supply_chain_snapshots/types/create_project_entity_supply_chain_snapshot_request.py b/src/sayari/project_entity_supply_chain_snapshots/types/create_project_entity_supply_chain_snapshot_request.py
new file mode 100644
index 00000000..e5af5b03
--- /dev/null
+++ b/src/sayari/project_entity_supply_chain_snapshots/types/create_project_entity_supply_chain_snapshot_request.py
@@ -0,0 +1,31 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from ...core.pydantic_utilities import UniversalBaseModel
+from ...core.pydantic_utilities import IS_PYDANTIC_V2
+import typing
+import pydantic
+
+
+class CreateProjectEntitySupplyChainSnapshotRequest(UniversalBaseModel):
+ """
+ Examples
+ --------
+ from sayari.project_entity_supply_chain_snapshots import (
+ CreateProjectEntitySupplyChainSnapshotRequest,
+ )
+
+ CreateProjectEntitySupplyChainSnapshotRequest(
+ label="Q1 2024 Supply Chain Analysis",
+ )
+ """
+
+ label: str
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/sayari/project_entity_supply_chain_snapshots/types/create_project_entity_supply_chain_snapshot_response.py b/src/sayari/project_entity_supply_chain_snapshots/types/create_project_entity_supply_chain_snapshot_response.py
new file mode 100644
index 00000000..f5fb9a10
--- /dev/null
+++ b/src/sayari/project_entity_supply_chain_snapshots/types/create_project_entity_supply_chain_snapshot_response.py
@@ -0,0 +1,31 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from ...core.pydantic_utilities import UniversalBaseModel
+from ...core.pydantic_utilities import IS_PYDANTIC_V2
+import typing
+import pydantic
+
+
+class CreateProjectEntitySupplyChainSnapshotResponse(UniversalBaseModel):
+ """
+ Examples
+ --------
+ from sayari.project_entity_supply_chain_snapshots import (
+ CreateProjectEntitySupplyChainSnapshotResponse,
+ )
+
+ CreateProjectEntitySupplyChainSnapshotResponse(
+ snapshot_id="nK9mP2",
+ )
+ """
+
+ snapshot_id: str
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/sayari/project_entity_supply_chain_snapshots/types/project_entity_supply_chain_snapshot_by_id_response.py b/src/sayari/project_entity_supply_chain_snapshots/types/project_entity_supply_chain_snapshot_by_id_response.py
new file mode 100644
index 00000000..15edb5de
--- /dev/null
+++ b/src/sayari/project_entity_supply_chain_snapshots/types/project_entity_supply_chain_snapshot_by_id_response.py
@@ -0,0 +1,109 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from ...core.pydantic_utilities import UniversalBaseModel
+from .project_entity_supply_chain_snapshot_detail_data import ProjectEntitySupplyChainSnapshotDetailData
+from ...core.pydantic_utilities import IS_PYDANTIC_V2
+import typing
+import pydantic
+
+
+class ProjectEntitySupplyChainSnapshotByIdResponse(UniversalBaseModel):
+ """
+ Examples
+ --------
+ from sayari.project_entity_supply_chain_snapshots import (
+ ProjectEntitySupplyChainSnapshotByIdResponse,
+ ProjectEntitySupplyChainSnapshotDetailData,
+ SupplyChainEdge,
+ SupplyChainNode,
+ )
+
+ ProjectEntitySupplyChainSnapshotByIdResponse(
+ data=ProjectEntitySupplyChainSnapshotDetailData(
+ snapshot_id="nK9mP2",
+ label="Production Supply Chain Analysis",
+ release_tag="20250115143000_prod",
+ partial_results=True,
+ explored_count=15,
+ created_at="2025-01-15 14:30:00.12345+00",
+ updated_at="2025-01-15 14:30:00.12345+00",
+ nodes=[
+ SupplyChainNode(
+ id="xG8wYP",
+ entity_id="oSlRbVMw4JdQ_R0nTd7yaQ",
+ label="TechCorp Inc",
+ type="company",
+ risk_factors=[
+ "export_controls",
+ "former_wro_entity",
+ "export_to_soe",
+ ],
+ countries=["USA", "CHN"],
+ ),
+ SupplyChainNode(
+ id="6GaxYn",
+ entity_id="rSoUePz7MgU_U3qWg0bdT",
+ label="Trade Partners Ltd",
+ type="company",
+ risk_factors=[
+ "export_controls",
+ "former_wro_entity",
+ "export_to_soe",
+ ],
+ countries=["RUS", "IRN"],
+ ),
+ SupplyChainNode(
+ id="JGlwYl",
+ entity_id="sTpVfQa8NhV_V4rXh1ceU",
+ label="International Logistics",
+ type="company",
+ risk_factors=["export_to_soe"],
+ countries=["GBR", "NLD"],
+ ),
+ ],
+ edges=[
+ SupplyChainEdge(
+ id="xG8wYP",
+ src_id="6GaxYn",
+ dst_id="xG8wYP",
+ departure_countries=["AFG"],
+ arrival_countries=["AFG", "AGO"],
+ hs_code="0303",
+ min_date="51969-08-29T00:00:00+00:00",
+ max_date="52971-09-25T00:00:00+00:00",
+ ),
+ SupplyChainEdge(
+ id="6GaxYn",
+ src_id="6GaxYn",
+ dst_id="JGlwYl",
+ departure_countries=["AFG"],
+ arrival_countries=["AFG", "AGO"],
+ hs_code="0304",
+ min_date="51969-08-29T00:00:00+00:00",
+ max_date="52971-09-25T00:00:00+00:00",
+ ),
+ SupplyChainEdge(
+ id="V03eYM",
+ src_id="xG8wYP",
+ dst_id="JGlwYl",
+ departure_countries=["USA", "CHN"],
+ arrival_countries=["GBR", "NLD"],
+ hs_code="0303",
+ min_date="51969-08-29T00:00:00+00:00",
+ max_date="52971-09-25T00:00:00+00:00",
+ ),
+ ],
+ ),
+ )
+ """
+
+ data: ProjectEntitySupplyChainSnapshotDetailData
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/sayari/project_entity_supply_chain_snapshots/types/project_entity_supply_chain_snapshot_data.py b/src/sayari/project_entity_supply_chain_snapshots/types/project_entity_supply_chain_snapshot_data.py
new file mode 100644
index 00000000..93cadf01
--- /dev/null
+++ b/src/sayari/project_entity_supply_chain_snapshots/types/project_entity_supply_chain_snapshot_data.py
@@ -0,0 +1,25 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from ...core.pydantic_utilities import UniversalBaseModel
+from ...core.pydantic_utilities import IS_PYDANTIC_V2
+import typing
+import pydantic
+
+
+class ProjectEntitySupplyChainSnapshotData(UniversalBaseModel):
+ snapshot_id: str
+ label: str
+ release_tag: str
+ partial_results: bool
+ explored_count: int
+ created_at: str
+ updated_at: str
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/sayari/project_entity_supply_chain_snapshots/types/project_entity_supply_chain_snapshot_detail_data.py b/src/sayari/project_entity_supply_chain_snapshots/types/project_entity_supply_chain_snapshot_detail_data.py
new file mode 100644
index 00000000..0fd57ee5
--- /dev/null
+++ b/src/sayari/project_entity_supply_chain_snapshots/types/project_entity_supply_chain_snapshot_detail_data.py
@@ -0,0 +1,29 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from ...core.pydantic_utilities import UniversalBaseModel
+import typing
+from .supply_chain_node import SupplyChainNode
+from .supply_chain_edge import SupplyChainEdge
+from ...core.pydantic_utilities import IS_PYDANTIC_V2
+import pydantic
+
+
+class ProjectEntitySupplyChainSnapshotDetailData(UniversalBaseModel):
+ snapshot_id: str
+ label: str
+ release_tag: str
+ partial_results: bool
+ explored_count: int
+ created_at: str
+ updated_at: str
+ nodes: typing.List[SupplyChainNode]
+ edges: typing.List[SupplyChainEdge]
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/sayari/project_entity_supply_chain_snapshots/types/project_entity_supply_chain_snapshots_response.py b/src/sayari/project_entity_supply_chain_snapshots/types/project_entity_supply_chain_snapshots_response.py
new file mode 100644
index 00000000..3a41347c
--- /dev/null
+++ b/src/sayari/project_entity_supply_chain_snapshots/types/project_entity_supply_chain_snapshots_response.py
@@ -0,0 +1,43 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from ...core.pydantic_utilities import UniversalBaseModel
+import typing
+from .project_entity_supply_chain_snapshot_data import ProjectEntitySupplyChainSnapshotData
+from ...core.pydantic_utilities import IS_PYDANTIC_V2
+import pydantic
+
+
+class ProjectEntitySupplyChainSnapshotsResponse(UniversalBaseModel):
+ """
+ Examples
+ --------
+ from sayari.project_entity_supply_chain_snapshots import (
+ ProjectEntitySupplyChainSnapshotData,
+ ProjectEntitySupplyChainSnapshotsResponse,
+ )
+
+ ProjectEntitySupplyChainSnapshotsResponse(
+ data=[
+ ProjectEntitySupplyChainSnapshotData(
+ snapshot_id="xG8wYP",
+ label="My REST Snapshot",
+ release_tag="20220429212557_test",
+ partial_results=False,
+ explored_count=6,
+ created_at="2025-08-12 20:13:20.49643+00",
+ updated_at="2025-08-12 20:13:20.49643+00",
+ )
+ ],
+ )
+ """
+
+ data: typing.List[ProjectEntitySupplyChainSnapshotData]
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/sayari/project_entity_supply_chain_snapshots/types/supply_chain_edge.py b/src/sayari/project_entity_supply_chain_snapshots/types/supply_chain_edge.py
new file mode 100644
index 00000000..14e9afd2
--- /dev/null
+++ b/src/sayari/project_entity_supply_chain_snapshots/types/supply_chain_edge.py
@@ -0,0 +1,26 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from ...core.pydantic_utilities import UniversalBaseModel
+import typing
+from ...core.pydantic_utilities import IS_PYDANTIC_V2
+import pydantic
+
+
+class SupplyChainEdge(UniversalBaseModel):
+ id: str
+ src_id: str
+ dst_id: str
+ departure_countries: typing.List[str]
+ arrival_countries: typing.List[str]
+ hs_code: str
+ min_date: str
+ max_date: str
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/sayari/project_entity_supply_chain_snapshots/types/supply_chain_node.py b/src/sayari/project_entity_supply_chain_snapshots/types/supply_chain_node.py
new file mode 100644
index 00000000..8280a316
--- /dev/null
+++ b/src/sayari/project_entity_supply_chain_snapshots/types/supply_chain_node.py
@@ -0,0 +1,24 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from ...core.pydantic_utilities import UniversalBaseModel
+import typing
+from ...core.pydantic_utilities import IS_PYDANTIC_V2
+import pydantic
+
+
+class SupplyChainNode(UniversalBaseModel):
+ id: str
+ entity_id: str
+ label: str
+ type: str
+ risk_factors: typing.List[str]
+ countries: typing.List[str]
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/sayari/search/types/entity_search_response.py b/src/sayari/search/types/entity_search_response.py
index 93f5c5bd..b646a4be 100644
--- a/src/sayari/search/types/entity_search_response.py
+++ b/src/sayari/search/types/entity_search_response.py
@@ -155,6 +155,7 @@ class EntitySearchResponse(PaginatedResponse):
"address": 6,
},
reference_id="ecdfb3f2ecc8c3797e77d5795a8066ef/06517802/1540252800000:4a34442eccf1622995130b194a5d50e7",
+ logistics_entity=False,
coordinates=[
Coordinates(
lat=51.49322001798694,
diff --git a/src/sayari/search/types/filter_list.py b/src/sayari/search/types/filter_list.py
index 7df412d8..99a0b6e2 100644
--- a/src/sayari/search/types/filter_list.py
+++ b/src/sayari/search/types/filter_list.py
@@ -21,6 +21,11 @@ class FilterList(UniversalBaseModel):
List of source IDs to filter by.
"""
+ source_country: typing.Optional[typing.List[Country]] = pydantic.Field(default=None)
+ """
+ List of source countries to filter by. Must be specified as trigrams, e.g. ATF.
+ """
+
country: typing.Optional[typing.List[Country]] = pydantic.Field(default=None)
"""
List of countries to filter by.
diff --git a/src/sayari/shared_types/types/core_entity.py b/src/sayari/shared_types/types/core_entity.py
index 276667c6..17b30c92 100644
--- a/src/sayari/shared_types/types/core_entity.py
+++ b/src/sayari/shared_types/types/core_entity.py
@@ -103,6 +103,7 @@ class CoreEntity(EntitySummary):
edited_by: typing.Optional[str] = None
editable: typing.Optional[bool] = None
upload: typing.Optional[str] = None
+ logistics_entity: typing.Optional[bool] = 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/sayari/shared_types/types/embedded_entity.py b/src/sayari/shared_types/types/embedded_entity.py
index c34c8e95..0200ca1c 100644
--- a/src/sayari/shared_types/types/embedded_entity.py
+++ b/src/sayari/shared_types/types/embedded_entity.py
@@ -111,6 +111,7 @@ class EmbeddedEntity(UniversalBaseModel):
user_related_entities_count: int
user_record_count: int
reference_id: typing.Optional[str] = None
+ logistics_entity: typing.Optional[bool] = 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/sayari/supply_chain/client.py b/src/sayari/supply_chain/client.py
index 90dd32cd..158f43b0 100644
--- a/src/sayari/supply_chain/client.py
+++ b/src/sayari/supply_chain/client.py
@@ -33,6 +33,8 @@ def upstream_trade_traversal(
self,
id: str,
*,
+ product: typing.Optional[typing.Sequence[str]] = None,
+ not_product: typing.Optional[typing.Sequence[str]] = None,
risk: typing.Optional[typing.Sequence[Risk]] = None,
not_risk: typing.Optional[typing.Sequence[Risk]] = None,
countries: typing.Optional[typing.Sequence[Country]] = None,
@@ -44,8 +46,6 @@ def upstream_trade_traversal(
tier_3_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
tier_4_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
tier_5_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
- product: typing.Optional[typing.Sequence[str]] = None,
- not_product: typing.Optional[typing.Sequence[str]] = None,
component: typing.Optional[typing.Sequence[str]] = None,
not_component: typing.Optional[typing.Sequence[str]] = None,
min_date: typing.Optional[str] = None,
@@ -62,6 +62,12 @@ def upstream_trade_traversal(
id : str
The root entity identifier.
+ product : typing.Optional[typing.Sequence[str]]
+ Product root edge filter. Filters results to include only trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.
+
+ not_product : typing.Optional[typing.Sequence[str]]
+ Product root edge filter. Filters results to exclude any trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.
+
risk : typing.Optional[typing.Sequence[Risk]]
Risk leaf node filter. Only return supply chains that end with a supplier that has 1+ of the specified risk factors.
@@ -95,12 +101,6 @@ def upstream_trade_traversal(
tier_5_shipment_country : typing.Optional[typing.Sequence[Country]]
Filters supply chain paths where 1+ shipment country from tier 5 matches the provided values.
- product : typing.Optional[typing.Sequence[str]]
- Product root edge filter. Only return supply chains that start with an edge that has 1+ of the specified HS codes.
-
- not_product : typing.Optional[typing.Sequence[str]]
- Product root edge filter. Only return supply chains that start with an edge that has none of the specified HS codes.
-
component : typing.Optional[typing.Sequence[str]]
Component edge filter. Only return supply chains that contain at least one edge with 1+ of the specified HS codes.
@@ -145,6 +145,8 @@ def upstream_trade_traversal(
f"v1/supply_chain/upstream/{jsonable_encoder(id)}",
method="GET",
params={
+ "product": product,
+ "-product": not_product,
"risk": risk,
"-risk": not_risk,
"countries": countries,
@@ -156,8 +158,6 @@ def upstream_trade_traversal(
"tier3_shipment_country": tier_3_shipment_country,
"tier4_shipment_country": tier_4_shipment_country,
"tier5_shipment_country": tier_5_shipment_country,
- "product": product,
- "-product": not_product,
"component": component,
"-component": not_component,
"min_date": min_date,
@@ -250,6 +250,8 @@ async def upstream_trade_traversal(
self,
id: str,
*,
+ product: typing.Optional[typing.Sequence[str]] = None,
+ not_product: typing.Optional[typing.Sequence[str]] = None,
risk: typing.Optional[typing.Sequence[Risk]] = None,
not_risk: typing.Optional[typing.Sequence[Risk]] = None,
countries: typing.Optional[typing.Sequence[Country]] = None,
@@ -261,8 +263,6 @@ async def upstream_trade_traversal(
tier_3_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
tier_4_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
tier_5_shipment_country: typing.Optional[typing.Sequence[Country]] = None,
- product: typing.Optional[typing.Sequence[str]] = None,
- not_product: typing.Optional[typing.Sequence[str]] = None,
component: typing.Optional[typing.Sequence[str]] = None,
not_component: typing.Optional[typing.Sequence[str]] = None,
min_date: typing.Optional[str] = None,
@@ -279,6 +279,12 @@ async def upstream_trade_traversal(
id : str
The root entity identifier.
+ product : typing.Optional[typing.Sequence[str]]
+ Product root edge filter. Filters results to include only trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.
+
+ not_product : typing.Optional[typing.Sequence[str]]
+ Product root edge filter. Filters results to exclude any trade relationships where the associated component is part of the specified product's blueprint or is a sub-component of that product.
+
risk : typing.Optional[typing.Sequence[Risk]]
Risk leaf node filter. Only return supply chains that end with a supplier that has 1+ of the specified risk factors.
@@ -312,12 +318,6 @@ async def upstream_trade_traversal(
tier_5_shipment_country : typing.Optional[typing.Sequence[Country]]
Filters supply chain paths where 1+ shipment country from tier 5 matches the provided values.
- product : typing.Optional[typing.Sequence[str]]
- Product root edge filter. Only return supply chains that start with an edge that has 1+ of the specified HS codes.
-
- not_product : typing.Optional[typing.Sequence[str]]
- Product root edge filter. Only return supply chains that start with an edge that has none of the specified HS codes.
-
component : typing.Optional[typing.Sequence[str]]
Component edge filter. Only return supply chains that contain at least one edge with 1+ of the specified HS codes.
@@ -370,6 +370,8 @@ async def main() -> None:
f"v1/supply_chain/upstream/{jsonable_encoder(id)}",
method="GET",
params={
+ "product": product,
+ "-product": not_product,
"risk": risk,
"-risk": not_risk,
"countries": countries,
@@ -381,8 +383,6 @@ async def main() -> None:
"tier3_shipment_country": tier_3_shipment_country,
"tier4_shipment_country": tier_4_shipment_country,
"tier5_shipment_country": tier_5_shipment_country,
- "product": product,
- "-product": not_product,
"component": component,
"-component": not_component,
"min_date": min_date,
diff --git a/src/sayari/traversal/types/shortest_path_response.py b/src/sayari/traversal/types/shortest_path_response.py
index c71ae635..de89c327 100644
--- a/src/sayari/traversal/types/shortest_path_response.py
+++ b/src/sayari/traversal/types/shortest_path_response.py
@@ -106,6 +106,7 @@ class ShortestPathResponse(UniversalBaseModel):
"address": 5,
},
reference_id="ecdfb3f2ecc8c3797e77d5795a8066ef/03389614/1540252800000:9030330caf25555c42c0bc0d84ea4aa1",
+ logistics_entity=False,
),
path=[
TraversalPath(
@@ -143,6 +144,7 @@ class ShortestPathResponse(UniversalBaseModel):
related_entities_count=179,
attribute_count={"country": 1, "address": 5, "name": 1},
reference_id="ac1fa195f9cd4ccf657bca3c6db0bb19/76232419/1717632000000:6d0f0edbd065319df4be58c3bc7909f5",
+ logistics_entity=False,
),
relationships={
"has_lawyer": TraversalRelationshipData(
diff --git a/src/sayari/traversal/types/traversal_response.py b/src/sayari/traversal/types/traversal_response.py
index da85d533..65c345c9 100644
--- a/src/sayari/traversal/types/traversal_response.py
+++ b/src/sayari/traversal/types/traversal_response.py
@@ -90,6 +90,7 @@ class TraversalResponse(UniversalBaseModel):
related_entities_count=1,
attribute_count={"name": 1, "address": 2, "country": 2},
reference_id="9139b58de1bdb0157a1a1e54e56df6d3/4781466/1649116800000:0ce01cbfaa586fcfb82164f0e5a010d5",
+ logistics_entity=False,
),
path=[
TraversalPath(
@@ -137,6 +138,7 @@ class TraversalResponse(UniversalBaseModel):
related_entities_count=1,
attribute_count={"name": 1, "address": 2, "country": 2},
reference_id="9139b58de1bdb0157a1a1e54e56df6d3/4781466/1649116800000:0ce01cbfaa586fcfb82164f0e5a010d5",
+ logistics_entity=False,
),
relationships={
"has_officer": TraversalRelationshipData(