From 0e8b16678ed698a10c6e05f07ad7d53f0152cdf9 Mon Sep 17 00:00:00 2001 From: Barrett Date: Tue, 1 Apr 2025 12:56:09 -0600 Subject: [PATCH 1/9] begin vehicle events setup --- dimo/api/vehicle_events.py | 34 ++++++++++++++++++++++++++++++++++ dimo/dimo.py | 2 ++ dimo/environments.py | 2 ++ 3 files changed, 38 insertions(+) create mode 100644 dimo/api/vehicle_events.py diff --git a/dimo/api/vehicle_events.py b/dimo/api/vehicle_events.py new file mode 100644 index 0000000..1ce5dd5 --- /dev/null +++ b/dimo/api/vehicle_events.py @@ -0,0 +1,34 @@ + + +class VehicleEvents: + + def __init__(self, request_method, get_auth_headers): + self._request = request_method + self._get_auth_headers = get_auth_headers + + def list_webhooks(self, developer_jwt: str): + pass + + def register_webhook(self, developer_jwt: str, request: str): + pass + + def webhook_signals(self, developer_jwt: str): + pass + + def update_webhook(self, developer_jwt: str, id: str, request: str): + pass + + def delete_webhook(self, developer_jwt: str, id: str): + pass + + def vehicle_subscriptions(self, developer_jwt: str): + pass + + def subscribe_vehicle(self, developer_jwt: str, token_id: str, event_id: str): + pass + + def unsubscribe_vehicle(self, developer_jwt: str, token_id: str, event_id: str): + pass + + + \ No newline at end of file diff --git a/dimo/dimo.py b/dimo/dimo.py index 2432a8d..0fa4943 100644 --- a/dimo/dimo.py +++ b/dimo/dimo.py @@ -4,6 +4,7 @@ from .api.token_exchange import TokenExchange from .api.trips import Trips from .api.valuations import Valuations +from .api.vehicle_events import VehicleEvents from .graphql.identity import Identity from .graphql.telemetry import Telemetry @@ -31,6 +32,7 @@ def __init__(self, env="Production"): self.trips = Trips(self.request, self._get_auth_headers) self.valuations = Valuations(self.request, self._get_auth_headers) self.telemetry = Telemetry(self) + self.vehicle_events = VehicleEvents(self.request, self._get_auth_headers) self._session = Request.session # Creates a full path for endpoints combining DIMO service, specific endpoint, and optional params diff --git a/dimo/environments.py b/dimo/environments.py index 94faf00..5195feb 100644 --- a/dimo/environments.py +++ b/dimo/environments.py @@ -9,6 +9,7 @@ "Trips": "https://trips-api.dimo.zone", "User": "https://users-api.dimo.zone", "Valuations": "https://valuations-api.dimo.zone", + "VehicleEvents": "https://vehicle-events-api.dimo.zone", }, "Dev": { "Attestation": "https://attestation-api.dev.dimo.zone", @@ -20,5 +21,6 @@ "Trips": "https://trips-api.dev.dimo.zone", "User": "https://users-api.dev.dimo.zone", "Valuations": "https://valuations-api.dev.dimo.zone", + "VehicleEvents": "https://vehicle-events-api.dev.dimo.zone", }, } From 02f4bc7a96d5f2e50890fb9ef93ed37eba4e0886 Mon Sep 17 00:00:00 2001 From: Barrett Date: Tue, 1 Apr 2025 13:13:09 -0600 Subject: [PATCH 2/9] webhook methods updated --- dimo/api/vehicle_events.py | 85 +++++++++++++++++++++++++++++++------- 1 file changed, 69 insertions(+), 16 deletions(-) diff --git a/dimo/api/vehicle_events.py b/dimo/api/vehicle_events.py index 1ce5dd5..8271154 100644 --- a/dimo/api/vehicle_events.py +++ b/dimo/api/vehicle_events.py @@ -1,3 +1,4 @@ +from dimo.errors import check_type class VehicleEvents: @@ -5,30 +6,82 @@ class VehicleEvents: def __init__(self, request_method, get_auth_headers): self._request = request_method self._get_auth_headers = get_auth_headers - + def list_webhooks(self, developer_jwt: str): - pass + check_type("developer_jwt", developer_jwt, str) + url = f"/webhooks" + return self._request( + "GET", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt) + ) - def register_webhook(self, developer_jwt: str, request: str): - pass + def register_webhook(self, developer_jwt: str, request: object): + check_type("developer_jwt", developer_jwt, str) + check_type("request", request, object) + url = f"/webhooks" + return self._request( + "POST", + "VehicleEvents", + url, + headers=self._get_auth_headers(developer_jwt), + json={"request": request}, + ) def webhook_signals(self, developer_jwt: str): - pass + check_type("developer_jwt", developer_jwt, str) + url = f"/webhooks/signals" + return self._request( + "GET", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt) + ) - def update_webhook(self, developer_jwt: str, id: str, request: str): - pass + def update_webhook(self, developer_jwt: str, id: str, request: object): + check_type("developer_jwt", developer_jwt, str) + check_type("id", id, str) + check_type("request", request, object) + url = f"/webhooks/{id}" + return self._request( + "PUT", + "VehicleEvents", + url, + headers=self._get_auth_headers(developer_jwt), + json=request, + ) def delete_webhook(self, developer_jwt: str, id: str): - pass - - def vehicle_subscriptions(self, developer_jwt: str): - pass + check_type("developer_jwt", developer_jwt, str) + check_type("id", id, str) + url = f"/webhooks/{id}" + return self._request( + "DELETE", + "VehicleEvents", + url, + headers=self._get_auth_headers(developer_jwt), + ) + + def vehicle_subscriptions(self, developer_jwt: str, token_id: str): + check_type("developer_jwt", developer_jwt, str) + check_type("token_id", token_id, str) + url = f"/subscriptions/{token_id}" + return self._request( + "GET", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt) + ) def subscribe_vehicle(self, developer_jwt: str, token_id: str, event_id: str): - pass + check_type("developer_jwt", developer_jwt, str) + check_type("token_id", token_id, str) + check_type("event_id", event_id, str) + url = f"/subscriptions/{token_id}/event/{event_id}" + return self._request( + "POST", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt) + ) def unsubscribe_vehicle(self, developer_jwt: str, token_id: str, event_id: str): - pass - - - \ No newline at end of file + check_type("developer_jwt", developer_jwt, str) + check_type("token_id", token_id, str) + check_type("event_id", event_id, str) + url = f"/subscriptions/{token_id}/event/{event_id}" + return self._request( + "DELETE", + "VehicleEvents", + url, + headers=self._get_auth_headers(developer_jwt), + ) From 9d2666a00945f7a63f579b22d4acf0806d7024f8 Mon Sep 17 00:00:00 2001 From: Barrett Date: Thu, 3 Apr 2025 11:45:57 -0600 Subject: [PATCH 3/9] final fixes to vehicle events --- dimo/api/vehicle_events.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dimo/api/vehicle_events.py b/dimo/api/vehicle_events.py index 8271154..d2db325 100644 --- a/dimo/api/vehicle_events.py +++ b/dimo/api/vehicle_events.py @@ -23,7 +23,7 @@ def register_webhook(self, developer_jwt: str, request: object): "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt), - json={"request": request}, + data=request, ) def webhook_signals(self, developer_jwt: str): @@ -65,13 +65,14 @@ def vehicle_subscriptions(self, developer_jwt: str, token_id: str): "GET", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt) ) - def subscribe_vehicle(self, developer_jwt: str, token_id: str, event_id: str): + def subscribe_vehicle(self, developer_jwt: str, token_id: str, event_id: str, request={}): check_type("developer_jwt", developer_jwt, str) check_type("token_id", token_id, str) check_type("event_id", event_id, str) + check_type("request", request, object) url = f"/subscriptions/{token_id}/event/{event_id}" return self._request( - "POST", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt) + "POST", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt), json=request ) def unsubscribe_vehicle(self, developer_jwt: str, token_id: str, event_id: str): From 69b9489dee6a5ec5817390be5445e6c1e83f2fdb Mon Sep 17 00:00:00 2001 From: Barrett Date: Thu, 3 Apr 2025 11:46:51 -0600 Subject: [PATCH 4/9] bump version 1.4.0 webhooks --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2e61bdd..4dd8d96 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "dimo-python-sdk" -version = "1.3.2" +version = "1.4.0" authors = [ { name="Barrett Kowalsky", email="barrettkowalsky@gmail.com" }, ] From f6f92d0221f98780a8dbc7a722cccbf9d8a1ed25 Mon Sep 17 00:00:00 2001 From: Barrett Date: Thu, 3 Apr 2025 14:01:39 -0600 Subject: [PATCH 5/9] fix --- dimo/api/vehicle_events.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dimo/api/vehicle_events.py b/dimo/api/vehicle_events.py index d2db325..523de67 100644 --- a/dimo/api/vehicle_events.py +++ b/dimo/api/vehicle_events.py @@ -43,7 +43,7 @@ def update_webhook(self, developer_jwt: str, id: str, request: object): "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt), - json=request, + data=request, ) def delete_webhook(self, developer_jwt: str, id: str): From de9d2df2fc79fb1e68e6a0441983de1baa9509a4 Mon Sep 17 00:00:00 2001 From: Barrett Date: Sun, 11 May 2025 08:07:41 -0600 Subject: [PATCH 6/9] update list all endpoint --- dimo/api/vehicle_events.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dimo/api/vehicle_events.py b/dimo/api/vehicle_events.py index 523de67..23f169d 100644 --- a/dimo/api/vehicle_events.py +++ b/dimo/api/vehicle_events.py @@ -7,9 +7,9 @@ def __init__(self, request_method, get_auth_headers): self._request = request_method self._get_auth_headers = get_auth_headers - def list_webhooks(self, developer_jwt: str): + def list_all_webhooks(self, developer_jwt: str): check_type("developer_jwt", developer_jwt, str) - url = f"/webhooks" + url = f"/v1/webhooks" return self._request( "GET", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt) ) From 5576d7d8e1cc18566e742a7d65ed7a6e032edcc9 Mon Sep 17 00:00:00 2001 From: Barrett Date: Sun, 11 May 2025 08:41:01 -0600 Subject: [PATCH 7/9] update vehicle events routes to v1 --- dimo/api/vehicle_events.py | 98 ++++++++++++++++++++++++++++++-------- dimo/dimo.py | 1 + 2 files changed, 78 insertions(+), 21 deletions(-) diff --git a/dimo/api/vehicle_events.py b/dimo/api/vehicle_events.py index 23f169d..31505a4 100644 --- a/dimo/api/vehicle_events.py +++ b/dimo/api/vehicle_events.py @@ -8,6 +8,9 @@ def __init__(self, request_method, get_auth_headers): self._get_auth_headers = get_auth_headers def list_all_webhooks(self, developer_jwt: str): + """ + Lists all webhooks for a given developer license + """ check_type("developer_jwt", developer_jwt, str) url = f"/v1/webhooks" return self._request( @@ -15,9 +18,12 @@ def list_all_webhooks(self, developer_jwt: str): ) def register_webhook(self, developer_jwt: str, request: object): + """ + Creates a new webhook under the developer license + """ check_type("developer_jwt", developer_jwt, str) check_type("request", request, object) - url = f"/webhooks" + url = f"/v1/webhooks" return self._request( "POST", "VehicleEvents", @@ -27,17 +33,45 @@ def register_webhook(self, developer_jwt: str, request: object): ) def webhook_signals(self, developer_jwt: str): + """ + Fetches the list of signal names available for the data field + """ check_type("developer_jwt", developer_jwt, str) - url = f"/webhooks/signals" + url = f"/v1/webhooks/signals" + return self._request( + "GET", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt) + ) + + def list_vehicle_subscriptions(self, developer_jwt: str, token_id: str): + """ + Lists all webhooks that a specified vehicle token id is subscribed to + """ + check_type("developer_jwt", developer_jwt, str) + check_type("token_id", token_id, str) + url = f"/v1/webhooks/vehicles/{token_id}" + return self._request( + "GET", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt) + ) + + def list_vehicle_subscriptions_by_event(self, developer_jwt: str, webhook_id: str): + """ + Lists all vehicle subscriptions for a given webhook id + """ + check_type("developer_jwt", developer_jwt, str) + check_type("webhook_id", webhook_id, str) + url = f"/v1/webhooks/{webhook_id}" return self._request( "GET", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt) ) - def update_webhook(self, developer_jwt: str, id: str, request: object): + def update_webhook(self, developer_jwt: str, webhook_id: str, request: object): + """ + Updates a webhook by a provided webhook id + """ check_type("developer_jwt", developer_jwt, str) - check_type("id", id, str) + check_type("webhook_id", webhook_id, str) check_type("request", request, object) - url = f"/webhooks/{id}" + url = f"/v1/webhooks/{webhook_id}" return self._request( "PUT", "VehicleEvents", @@ -46,10 +80,13 @@ def update_webhook(self, developer_jwt: str, id: str, request: object): data=request, ) - def delete_webhook(self, developer_jwt: str, id: str): + def delete_webhook(self, developer_jwt: str, webhook_id: str): + """ + Deletes a webhook by a provided webhook id + """ check_type("developer_jwt", developer_jwt, str) - check_type("id", id, str) - url = f"/webhooks/{id}" + check_type("webhook_id", webhook_id, str) + url = f"/v1/webhooks/{webhook_id}" return self._request( "DELETE", "VehicleEvents", @@ -57,29 +94,48 @@ def delete_webhook(self, developer_jwt: str, id: str): headers=self._get_auth_headers(developer_jwt), ) - def vehicle_subscriptions(self, developer_jwt: str, token_id: str): + def subscribe_all_vehicles(self, developer_jwt: str, webhook_id: str): + """ + Subscribes all vehicles to a specified webhook + """ check_type("developer_jwt", developer_jwt, str) - check_type("token_id", token_id, str) - url = f"/subscriptions/{token_id}" + check_type("webhook_id", webhook_id, str) + url = f"/v1/webhooks/{webhook_id}/subscribe/all" return self._request( - "GET", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt) + "POST", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt) ) - - def subscribe_vehicle(self, developer_jwt: str, token_id: str, event_id: str, request={}): + + def subscribe_vehicle(self, developer_jwt: str, token_id: str, webhook_id: str): + """ + Subscribes a single vehicle to a specified webhook + """ check_type("developer_jwt", developer_jwt, str) check_type("token_id", token_id, str) - check_type("event_id", event_id, str) - check_type("request", request, object) - url = f"/subscriptions/{token_id}/event/{event_id}" + check_type("webhook_id", webhook_id, str) + url = f"/v1/webhooks/{webhook_id}/subscribe/{token_id}" + return self._request( + "POST", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt) + ) + + def unsubscribe_all_vehicles(self, developer_jwt: str, webhook_id: str): + """ + Unsubscribes all vehicles from a specified webhook + """ + check_type("developer_jwt", developer_jwt, str) + check_type("webhook_id", webhook_id, str) + url = f"/v1/webhooks/{webhook_id}/unsubscribe/all" return self._request( - "POST", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt), json=request + "DELETE", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt) ) - def unsubscribe_vehicle(self, developer_jwt: str, token_id: str, event_id: str): + def unsubscribe_vehicle(self, developer_jwt: str, token_id: str, webhook_id: str): + """ + Unsubscribes a single vehicle from a specified webhook + """ check_type("developer_jwt", developer_jwt, str) check_type("token_id", token_id, str) - check_type("event_id", event_id, str) - url = f"/subscriptions/{token_id}/event/{event_id}" + check_type("webhook_id", webhook_id, str) + url = f"/v1/webhooks/{webhook_id}/unsubscribe/{token_id}" return self._request( "DELETE", "VehicleEvents", diff --git a/dimo/dimo.py b/dimo/dimo.py index 4dea156..7c7981f 100644 --- a/dimo/dimo.py +++ b/dimo/dimo.py @@ -81,6 +81,7 @@ def __getattr__(self, name: str) -> Any: "valuations": (Valuations, ("request", "_get_auth_headers")), "identity": (Identity, ("self",)), "telemetry": (Telemetry, ("self",)), + "vehicle_events": (VehicleEvents, ("request", "_get_auth_headers")), } if name in mapping: cls, deps = mapping[name] From cc205c7988a9017aff747f60022bbab0af5abb89 Mon Sep 17 00:00:00 2001 From: Barrett Date: Tue, 20 May 2025 07:03:00 -0600 Subject: [PATCH 8/9] formatting updates --- dimo/api/vehicle_events.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/dimo/api/vehicle_events.py b/dimo/api/vehicle_events.py index 31505a4..f964c72 100644 --- a/dimo/api/vehicle_events.py +++ b/dimo/api/vehicle_events.py @@ -41,7 +41,7 @@ def webhook_signals(self, developer_jwt: str): return self._request( "GET", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt) ) - + def list_vehicle_subscriptions(self, developer_jwt: str, token_id: str): """ Lists all webhooks that a specified vehicle token id is subscribed to @@ -52,8 +52,8 @@ def list_vehicle_subscriptions(self, developer_jwt: str, token_id: str): return self._request( "GET", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt) ) - - def list_vehicle_subscriptions_by_event(self, developer_jwt: str, webhook_id: str): + + def list_vehicle_subscriptions_by_event(self, developer_jwt: str, webhook_id: str): """ Lists all vehicle subscriptions for a given webhook id """ @@ -104,7 +104,7 @@ def subscribe_all_vehicles(self, developer_jwt: str, webhook_id: str): return self._request( "POST", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt) ) - + def subscribe_vehicle(self, developer_jwt: str, token_id: str, webhook_id: str): """ Subscribes a single vehicle to a specified webhook @@ -116,7 +116,7 @@ def subscribe_vehicle(self, developer_jwt: str, token_id: str, webhook_id: str): return self._request( "POST", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt) ) - + def unsubscribe_all_vehicles(self, developer_jwt: str, webhook_id: str): """ Unsubscribes all vehicles from a specified webhook @@ -125,7 +125,10 @@ def unsubscribe_all_vehicles(self, developer_jwt: str, webhook_id: str): check_type("webhook_id", webhook_id, str) url = f"/v1/webhooks/{webhook_id}/unsubscribe/all" return self._request( - "DELETE", "VehicleEvents", url, headers=self._get_auth_headers(developer_jwt) + "DELETE", + "VehicleEvents", + url, + headers=self._get_auth_headers(developer_jwt), ) def unsubscribe_vehicle(self, developer_jwt: str, token_id: str, webhook_id: str): From 107a5f41848ce5375aeac45d403914ea6bbd610c Mon Sep 17 00:00:00 2001 From: Barrett Date: Wed, 21 May 2025 10:37:06 -0600 Subject: [PATCH 9/9] README: Vehicle Events API --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index f86a8ea..f8235d9 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,28 @@ my_query = """ total_network_vehicles = dimo.identity.query(query=my_query) ``` +### Vehicle Events API (DIMO Webhooks) + +The SDK supports calls to the Vehicle Events API, including: registering a new webhook, subscribing and unsubscribing vehicles, checking vehicles subscribed to a specific webhook, and more. To view all the available methods, check out the [Vehicle Events API Documentation here](https://docs.dimo.org/developer-platform/vehicle-events-api-webhooks). + +Here's a sample of how you might register a new webhook: + +```python + +new_webhook_config = { + "service": "Telemetry", + "data": "powertrainTransmissionTravelledDistance", + "trigger": "valueNumber > 10000", + "setup": "Realtime", + "description": "Trigger when odometer above 10000 km", + "target_uri": "https://my-target-uri.com/webhook", + "status": "Active", + "verification_token": "abc" +} + +dimo.vehicle_events.register_webhook(developer_jwt=dev_jwt, request=new_webhook_config) +``` + ## How to Contribute to the SDK You can read more about contributing [here](https://github.com/DIMO-Network/dimo-python-sdk/blob/dev-barrettk/CONTRIBUTING.md)