Device roaming status
The Device Status SDK allows checking the device roaming status and subscribing to its related events. A device can be in national (different networks in the same country) or international roaming (different networks in another country). Knowing whether the device is connected to a network other than its home one is important for regulatory, security and content delivery reasons.
For example, in some cases for certain transactions to take place, a device needs to be within an area where it is legally allowed to operate or make transactions. Another case would be to ensure a customer's device is exactly where it claims to be to avoid fraud. Other important examples include content or service delivery to avoid extra costs or unexpected roaming charges for accessing them.
Subscribe to Roaming Status events
The snippet below will show you how to create a Device Status roaming subscription.
Note that the snippet below require you to identify your mobile network device.
import network_as_code as nac
from network_as_code.models.device import DeviceIpv4Addr
from network_as_code.models.device_status import EventType, AccessTokenCredential
# We begin by creating a Network as Code client
client = nac.NetworkAsCodeClient(
token="<your-application-key-here>"
)
# Then, we create an object for the mobile device we want to use
my_device = client.devices.get(
phone_number="+99999991000"
)
# Then we subscribe your device to roaming status events.
my_subscription = client.device_status.subscribe(
device=my_device,
event_type=[EventType.ROAMING_STATUS],
# Use HTTPS to send notifications
sink="https://example.com/notify",
# You can also add optional parameters
max_num_of_reports=5,
subscription_expire_time=datetime.now(timezone.utc) + timedelta(days=1),
sink_credential=AccessTokenCredential(
access_token= "some-access-token",
access_token_expires_utc= datetime.now(timezone.utc) + timedelta(days=1),
access_token_type="bearer"
),
initial_event=True
)
# Use this to show the roaming subscription status
print(my_subscription)Roaming subscription parameters
| Parameters | Type | Description | Mandatory or Optional |
|---|---|---|---|
event_type | object/string | The status type you want to check. For example EventType.ROAMING_STATUS or org.camaraproject.device-roaming-status-subscriptions.v0.roaming-status. | Mandatory |
device | object | The device object created for the mobile device we want to use. | Mandatory |
sink | string | The recipient's HTTP endpoint, which is a web server configured to receive POST requests. | Mandatory |
sink_credential | object | Contains authorization information for delivery of notifications. | Optional |
credential_type | string | The type of credential. If provided, must be set to "ACCESSTOKEN". | Optional |
access_token | string | Previously acquired access token. | Optional |
access_token_type | string | The type of the access token. If provided, must be set to "bearer". | Optional |
access_token_expires_utc | object/string | When the access token expires. Can be either a date-time object or RFC 3339 formatted date string, for example "2025-12-03T12:27:08.312Z". Must have a time zone. | Optional |
initial_event | boolean | Should be set to true, if a notification should be sent when the subscription is created and the status reflects the event request. | Optional |
subscription_max_events | integer | Maximum amount of notifications to be sent. Once this amount is reached, the subscription ends. If a notification is sent due to initial_event being set to true, this counts towards the subscription_max_events. | Optional |
subscription_expire_time | object/string | When the subscription should expire. Can be either a date-time object or ISO 8601 formatted date string, for example "2025-08-28T12:40:20.398Z". | Optional |
Roaming event types
| Event type | Type | Description |
|---|---|---|
roaming-status | object/string | EventType.ROAMING_STATUS or org.camaraproject.device-roaming-status-subscriptions.v0.roaming-status - Used for receiving updates about when the device switches from roaming ON to roaming OFF and conversely. |
roaming-on | object/string | EventType.ROAMING_ON or org.camaraproject.device-roaming-status-subscriptions.v0.roaming-on - Used to receive updates when the device switches from roaming OFF to roaming ON. |
roaming-off | object/string | EventType.ROAMING_OFF or org.camaraproject.device-roaming-status-subscriptions.v0.roaming-off - Used to receive updates when the device switches from roaming ON to roaming OFF. |
roaming-change-country | object/string | EventType.ROAMING_CHANGE_COUNTRY or org.camaraproject.device-roaming-status-subscriptions.v0.roaming-change-country - Notification is sent when the device in roaming changes country code. |
Simulated Device Roaming scenarios
The Network as Code simulators have been configured to provide specific device roaming results for specific simulated devices based on their device identifier. This will be helpful in testing your code against the different responses, including possible errors, by simply substituting the device identifier in your code.
The device identifiers and their responses can be found in the following table:
| Device identifier type | Device identifier | HTTP status code | HTTP status code description | Reponse description |
|---|---|---|---|---|
| Phone Number | +99999991000 | 200 | Success | Device is roaming |
| Phone Number | +99999991001 | 200 | Success | Device is not roaming |
| Phone Number | +99999990400 | 400 | Bad Request | |
| Phone Number | +99999990404 | 404 | Not found | |
| Phone Number | +99999990422 | 422 | Unprocessable Content | |
| Phone Number | +99999990500 | 500 | Internal Server Error | |
| Phone Number | +99999990502 | 502 | Bad Gateway | |
| Phone Number | +99999990503 | 503 | Service Unavailable | |
| Phone Number | +99999990504 | 504 | Gateway Timeout |
Getting a device status roaming subscription
The snippet below will show you how to retrieve a roaming subscription. If you need to modify or delete your subscription, you can easily retrieve it by its ID.
# Get the subscription previously created by its ID
subscription = client.device_status.get_roaming_subscription("<my-subscription-id>")You can also get a list of active Device Status subscriptions for a client:
subscriptions = client.device_status.get_subscriptions()Deleting Device Status roaming subscriptions
Use the following snippet to delete a Device Status roaming subscription, if you wish to stop receiving the previously configured status notifications.
# Get a previously created subscription by its ID
subscription = client.device_status.get_roaming_subscription("<my-subscription-id>")
# And delete it:
subscription.delete()Getting a devices roaming status
You can check the device roaming status like so:
print(my_device.get_roaming())Getting device roaming status responses
| Response | Type | Description |
|---|---|---|
roaming | boolean | Value is true if the device is roaming and false otherwise. |
countryCode | integer | Present, if the device is roaming. The Mobile country code (MCC), indentifying the country and dependent areas. For example 340. |
countryName | array | Present, if the device is roaming. ISO 3166 ALPHA-2 country-codes mapped to an MCC. One MCC can have multiple countries mapped to it, in which case the countries are listed in the returned array. For example ["BL", "GF", "GP", "MF", "MQ"]. If no country is mapped to the MCC, the returned array is empty. |
lastStatusTime | string | If present, specifies the time when the status was last updated. A date-time string, for example "2025-12-20T10:41:38.657Z". If absent, indicates that the information may be outdated or the freshness uncertain. |
Getting roaming notifications
The code snippet below will set up an HTTP server with a POST endpoint. This will allow receiving device roaming status updates. Learn more about the notification URL/auth token and how to create an HTTP server with a POST endpoint for roaming notifications.
Roaming notification handler
# status_handler.py
# run with: uvicorn status_handler:app
from fastapi import FastAPI, Header
from pydantic import BaseModel
from typing_extensions import Annotated
from typing import List, Union
app = FastAPI()
class Device(BaseModel):
phoneNumber: Optional[str] | None
networkAccessIdentifier: Optional[str] | None
ipv4Address: Optional[str] | None
ipv6Address: Optional[str] | None
class RoamingEventDetail(BaseModel):
device: Device
subscriptionId: str
roaming: bool | None
countryCode: int | None
countryName: List[str] | None
lastStatusTime: str | None
terminationReason: str
class Event(BaseModel):
eventTime: str
eventDetail: RoamingEventDetail
class Data(BaseModel):
device: Device
subscriptionId: str
roaming: RoamingEventDetail
class RoamingStatusNotification(BaseModel):
id: str
source: str
type: str
specversion: str
datacontenttype: str
time: str
eventSubscriptionId: str
event: Event
data: Data
@app.post("/notifications")
def receive_notification(
notification: RoamingStatusNotification,
):
print(notification)Roaming notification details
This is the notification JSON schema for roaming related notifications.
Remember that the string values represented below are just examples that can be used. So, they should contain your real device-status values.
{
"id": "2628b42e-8789-4fcd-942a-841f16f52897",
"source": "/device-status/device-roaming-status-subscriptions/v0.7/subscriptions/90409561-68f5-4360-b12d-9003f4dca8b0",
"type": "org.camaraproject.device-roaming-status-subscriptions.v0.roaming-status",
"specversion": "1.0",
"datacontenttype": "application/json",
"time": "2026-04-17T07:31:01.416474Z",
"data": {
"device": {
"phoneNumber": "+99999991000",
"networkAccessIdentifier": "[email protected]",
"ipv4Address": {
"publicAddress": "233.252.0.2",
"privateAddress": "192.0.2.25",
"publicPort": 80
},
"ipv6Address": "2001:db8:1234:5678:9abc:def0:fedc:ba98"
},
"subscriptionId": "90409561-68f5-4360-b12d-9003f4dca8b0",
"roaming": true,
"countryCode": 901
"countryName": []
}
}
Subscription-ends notification
This is the notification JSON schema for monitoring why a device's subscription ended.
{
"id":"2628b42e-8789-4fcd-942a-841f16f52897",
"source":"/device-status/device-roaming-status-subscriptions/v0.7/subscriptions/f76c90dd-3f68-4c69-bbdc-57bddfd0f910",
"type":"org.camaraproject.device-roaming-status-subscriptions.v0.subscription-ends",
"specversion":"1.0",
"datacontenttype":"application/json",
"time":"2027-04-17T07:31:01.416474Z",
"data":{
"device":{
"phoneNumber":"+99999991000",
"ipv4Address": {
"publicAddress": "233.252.0.2",
"privateAddress": "192.0.2.25",
"publicPort": 80
},
"ipv6Address": "2001:db8:1234:5678:9abc:def0:fedc:ba98"
},
"subscriptionId":"f76c90dd-3f68-4c69-bbdc-57bddfd0f910",
"terminationReason":"SUBSCRIPTION_EXPIRED"
}
}
Supported event types
| Notification type | Type | Description |
|---|---|---|
subscription-ends | string | org.camaraproject.device-roaming-status-subscriptions.v0.subscription-ends - Device Status roaming notification subscription has expired. |
Subscription-ends keywords
| Subscription-ends-keyword values | Type | Description |
|---|---|---|
terminationReason | string | Value containing the termination reason. For example if subscription expire time has been reached "SUBSCRIPTION_EXPIRED" or if the API server has stopped sending notifications "NETWORK_TERMINATED". |
Shared-keyword values
Check the table below for further information on mandatory, optional values and their types.
The values described here are common to all the Device-Status notification JSON schemas:
| Keyword values | Type | Description |
|---|---|---|
subscriptionId | string | The event subscription identifier. |
source | string | Identifies the source where the event happened. It contains the Network as Code API implementation and subscription ID. |
type | string | The status type being checked and returned by the API. For example roaming-status. |
specversion | string | Representing the specification version. |
datacontenttype | string | Indicates the media type for the event payload encoding. It must be "application/json" in the context of CAMARA APIs |
time | string | The time the event occurred. Date and time are specified in ISO 8601 format, e.g.: "2023-08-20T21:01:02.345Z". |
Device identifiers
| Keyword values | Type | Description | Mandatory or Optional |
|---|---|---|---|
data | object | Object that will contain other objects or strings. Contains multiple device status data, e.g. the subscription id. | Mandatory |
device | object | Object that will contain other objects or strings. Contains multiple device identifiers, e.g. the devices phone number. | Mandatory |
phoneNumber | string | Phone number of the device, with a pattern that matches "^[+]?[0-9]{5,15}$" or a null value. | Optional |
ipv4Address | object | Contains an object for IPv4 address values or a null value. It refers to the IPv4 address of the device. An IP address is needed for some flow-oriented services, such as QoD. | Optional |
publicAddress | string | Either the device's public IPv4 address, the Network Address Translation (NAT) behind it or a null value. Learn more about NAT.. | Optional |
privateAddress | string | The device's private IPv4 address if it is behind NAT or a null value. | Optional |
publicPort | integer | The public port used by the device or a null value. A port is necessary, as private address ranges overlap, and public port is used to extend the range for Carrier-grade NAT (CGNAT), a type of large-scale NAT. | Optional |
ipv6Address | string | Contains the device's IPv6 address or a null value. An IP address is needed for some flow-oriented services, such as QoD. | Optional |
Last updated December 19, 2025