Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ This is the Python server SDK to help you use Vonage APIs in your Python applica
- [Application API](#application-api)
- [HTTP Client](#http-client)
- [JWT Client](#jwt-client)
- [Identity Insights](#identity-insights)
- [Messages API](#messages-api)
- [Network Number Verification API](#network-number-verification-api)
- [Network Sim Swap API](#network-sim-swap-api)
Expand Down Expand Up @@ -403,6 +404,34 @@ from vonage_jwt import verify_signature
verify_signature(TOKEN, SIGNATURE_SECRET) # Returns a boolean
```

## Identity Insights

### Get Insights

```python
from vonage_identity_insights import (
IdentityInsightsRequest,
InsightsRequest,
EmptyInsight,
SimSwapInsight,
)

options = HttpClientOptions(api_host='api-eu.vonage.com', timeout=30)

client = Vonage(auth=auth, http_client_options=options)

request = IdentityInsightsRequest(
phone_number='1234567890',
purpose='FraudPreventionAndDetection',
insights=InsightsRequest(
format=EmptyInsight(),
sim_swap=SimSwapInsight(period=240)
)
)

response = client.identity_insights.get_insights(request)
```

## Messages API

### How to Construct a Message
Expand Down Expand Up @@ -1436,6 +1465,7 @@ The following is a list of Vonage APIs and whether the Python SDK provides suppo
| External Accounts API | Beta | ❌ |
| Media API | Beta | ❌ |
| Messages API | General Availability | ✅ |
| Identity Insights API | General Availability | ✅ |
| Number Insight API | General Availability | ✅ |
| Number Management API | General Availability | ✅ |
| Pricing API | General Availability | ✅ |
Expand Down
3 changes: 1 addition & 2 deletions account/tests/test_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import responses
from pytest import raises
from testutils import build_response, get_mock_api_key_auth
from vonage_account.account import Account
from vonage_account.errors import InvalidSecretError
from vonage_account.requests import (
Expand All @@ -12,8 +13,6 @@
from vonage_http_client.errors import ForbiddenError
from vonage_http_client.http_client import HttpClient

from testutils import build_response, get_mock_api_key_auth

path = abspath(__file__)

account = Account(HttpClient(get_mock_api_key_auth()))
Expand Down
3 changes: 1 addition & 2 deletions application/tests/test_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import responses
from pytest import raises
from testutils import build_response, get_mock_api_key_auth
from vonage_application.application import Application
from vonage_application.common import (
ApplicationUrl,
Expand All @@ -24,8 +25,6 @@
from vonage_application.requests import ApplicationConfig, ListApplicationsFilter
from vonage_http_client.http_client import HttpClient

from testutils import build_response, get_mock_api_key_auth

path = abspath(__file__)

application = Application(HttpClient(get_mock_api_key_auth()))
Expand Down
3 changes: 1 addition & 2 deletions http_client/tests/test_http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from requests import PreparedRequest, Response, Session
from requests.exceptions import ConnectionError
from responses import matchers
from testutils import build_response, get_mock_jwt_auth
from vonage_http_client.auth import Auth
from vonage_http_client.errors import (
AuthenticationError,
Expand All @@ -20,8 +21,6 @@
)
from vonage_http_client.http_client import HttpClient, HttpClientOptions

from testutils import build_response, get_mock_jwt_auth

path = abspath(__file__)


Expand Down
16 changes: 16 additions & 0 deletions identity_insights/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
resource(name='pyproject', source='pyproject.toml')
file(name='readme', source='README.md')

files(sources=['tests/data/*'])

python_distribution(
name='vonage-identity-insights',
dependencies=[
':pyproject',
':readme',
'identity_insights/src/vonage_identity_insights',
],
provides=python_artifact(),
generate_setup=False,
repositories=['@pypi'],
)
2 changes: 2 additions & 0 deletions identity_insights/CHANGES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# 1.0.0
- Initial upload
35 changes: 35 additions & 0 deletions identity_insights/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Vonage Identity Insights Package

This package contains the code to use the [Vonage Identity Insights API](https://developer.vonage.com/en/identity-insights/overview) in Python. The API provides real-time access to a broad range of attributes related to the carrier, subscriber, or device associated with a phone number. To use it you will need a Vonage account. Sign up [for free at vonage.com][signup].

## Usage

It is recommended to use this as part of the main `vonage` package. The examples below assume you've created an instance of the `vonage.Vonage` class called `vonage_client`.

### Make a Standard Identity Insights Request

```python
from vonage import Vonage, Auth, HttpClientOptions
from vonage_identity_insights import (
IdentityInsightsRequest,
InsightsRequest,
EmptyInsight,
SimSwapInsight,
)

options = HttpClientOptions(api_host="api-eu.vonage.com", timeout=30)

client = Vonage(auth=auth, http_client_options=options)

request = IdentityInsightsRequest(
phone_number="1234567890",
purpose="FraudPreventionAndDetection",
insights=InsightsRequest(
format=EmptyInsight(), sim_swap=SimSwapInsight(period=240)
),
)

response = client.identity_insights.get_insights(request)

```

32 changes: 32 additions & 0 deletions identity_insights/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[project]
name = 'vonage-identity-insights'
dynamic = ["version"]
description = 'Vonage Identity Insights package'
readme = "README.md"
authors = [{ name = "Vonage", email = "[email protected]" }]
requires-python = ">=3.9"
dependencies = [
"vonage-http-client>=1.5.0",
"vonage-utils>=1.1.4",
"pydantic>=2.9.2",
]
classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"License :: OSI Approved :: Apache Software License",
]

[project.urls]
homepage = "https://github.com/Vonage/vonage-python-sdk"

[tool.setuptools.dynamic]
version = { attr = "vonage_identity_insights._version.__version__" }

[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
1 change: 1 addition & 0 deletions identity_insights/src/vonage_identity_insights/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python_sources()
30 changes: 30 additions & 0 deletions identity_insights/src/vonage_identity_insights/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from . import errors
from .identity_insights import IdentityInsights
from .requests import (
EmptyInsight,
IdentityInsightsRequest,
InsightsRequest,
Location,
LocationCenter,
LocationVerificationInsight,
SimSwapInsight,
SubscriberMatchInsight,
)
from .responses import IdentityInsightsResponse, InsightStatus

__all__ = [
"IdentityInsights",
# Requests
"IdentityInsightsRequest",
"InsightsRequest",
"EmptyInsight",
"SimSwapInsight",
"SubscriberMatchInsight",
"LocationVerificationInsight",
"Location",
"LocationCenter",
# Responses
"IdentityInsightsResponse",
"InsightStatus",
"errors",
]
1 change: 1 addition & 0 deletions identity_insights/src/vonage_identity_insights/_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = "1.0.0"
9 changes: 9 additions & 0 deletions identity_insights/src/vonage_identity_insights/errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from vonage_utils.errors import VonageError


class IdentityInsightsError(VonageError):
"""Indicates an error when using the Vonage Identity Insights API."""


class EmptyInsightsRequestException(VonageError):
"""At least one insight must be provided."""
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
from logging import getLogger

from pydantic import validate_call
from vonage_http_client.http_client import HttpClient

from .errors import EmptyInsightsRequestException, IdentityInsightsError
from .requests import IdentityInsightsRequest
from .responses import IdentityInsightsResponse

logger = getLogger("vonage_identity_insights")


class IdentityInsights:
"""Calls Vonage's Identity Insights API."""

def __init__(self, http_client: HttpClient) -> None:
"""Initialize the IdentityInsights client.

Args:
http_client (HttpClient): Configured HTTP client used to make
authenticated requests to the Vonage API.
"""
self._http_client = http_client
self._auth_type = "jwt"

@property
def http_client(self) -> HttpClient:
"""The HTTP client used to make requests to the Vonage Indentity Insights API.

Returns:
HttpClient: The HTTP client used to make requests to the Identity Insights API.
"""
return self._http_client

@validate_call
def get_insights(
self, insights_request: IdentityInsightsRequest
) -> IdentityInsightsResponse:
"""Retrieve identity insights for a phone number.

Sends an aggregated request to the Identity Insights API and returns
the results for each requested insight.

Args:
insights_request (IdentityInsightsRequest): The request object
containing the phone number and the set of identity insights
to retrieve.

Returns:
IdentityInsightsResponse: The response object containing the results
and status of each requested insight.

Raises:
IdentityInsightsError: If the API returns an error response in
`application/problem+json` format.
"""
payload = insights_request.model_dump(exclude_none=True)

insights = payload.get("insights")
if not insights or not isinstance(insights, dict):
raise EmptyInsightsRequestException()

response = self._http_client.post(
self._http_client.api_host,
"/v0.1/identity-insights",
payload,
auth_type=self._auth_type,
)
self._check_for_error(response)

return IdentityInsightsResponse(**response)

def _check_for_error(self, response: dict) -> None:
"""Check whether the API response represents an error.

The Identity Insights API returns errors using the
`application/problem+json` format. If such an error is detected, this
method raises an IdentityInsightsError.

Args:
response (dict): Raw response returned by the HTTP client.

Raises:
IdentityInsightsError: If the response contains an error payload.
"""
if "title" in response and "detail" in response:
error_message = f"Error with the following details: {response}"
raise IdentityInsightsError(error_message)
Loading