diff --git a/.stats.yml b/.stats.yml
index c92480be..5893a877 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1 +1 @@
-configured_endpoints: 247
+configured_endpoints: 234
diff --git a/api.md b/api.md
index bfeceaed..c2d4ddc2 100644
--- a/api.md
+++ b/api.md
@@ -965,52 +965,6 @@ Methods:
- client.notifications.get_preferences() -> NotificationGetPreferencesResponse
- client.notifications.update_preferences(\*\*params) -> NotificationUpdatePreferencesResponse
-# Esims
-
-Types:
-
-```python
-from mobilerun_sdk.types import (
- EsimCreateResponse,
- EsimRetrieveResponse,
- EsimUpdateResponse,
- EsimListResponse,
- EsimCapacityResponse,
- EsimConfirmPaymentResponse,
- EsimImportResponse,
- EsimInstallResponse,
- EsimInstallStatusResponse,
- EsimSelectorResponse,
-)
-```
-
-Methods:
-
-- client.esims.create(\*\*params) -> EsimCreateResponse
-- client.esims.retrieve(id) -> EsimRetrieveResponse
-- client.esims.update(id, \*\*params) -> EsimUpdateResponse
-- client.esims.list(\*\*params) -> EsimListResponse
-- client.esims.delete(id) -> None
-- client.esims.capacity() -> EsimCapacityResponse
-- client.esims.confirm_payment(id) -> EsimConfirmPaymentResponse
-- client.esims.import\_(\*\*params) -> EsimImportResponse
-- client.esims.install(id, \*\*params) -> EsimInstallResponse
-- client.esims.install_status(id) -> EsimInstallStatusResponse
-- client.esims.selector(\*\*params) -> EsimSelectorResponse
-
-## Messages
-
-Types:
-
-```python
-from mobilerun_sdk.types.esims import MessageListResponse, MessageSendResponse
-```
-
-Methods:
-
-- client.esims.messages.list(id, \*\*params) -> MessageListResponse
-- client.esims.messages.send(id, \*\*params) -> MessageSendResponse
-
# Messages
Types:
diff --git a/src/mobilerun_sdk/_client.py b/src/mobilerun_sdk/_client.py
index 4a8abcae..cb8ba65a 100644
--- a/src/mobilerun_sdk/_client.py
+++ b/src/mobilerun_sdk/_client.py
@@ -38,7 +38,6 @@
if TYPE_CHECKING:
from .resources import (
apps,
- esims,
files,
store,
tasks,
@@ -64,7 +63,6 @@
from .resources.proxies import ProxiesResource, AsyncProxiesResource
from .resources.carriers import CarriersResource, AsyncCarriersResource
from .resources.profiles import ProfilesResource, AsyncProfilesResource
- from .resources.esims.esims import EsimsResource, AsyncEsimsResource
from .resources.store.store import StoreResource, AsyncStoreResource
from .resources.tasks.tasks import TasksResource, AsyncTasksResource
from .resources.notifications import NotificationsResource, AsyncNotificationsResource
@@ -249,12 +247,6 @@ def notifications(self) -> NotificationsResource:
return NotificationsResource(self)
- @cached_property
- def esims(self) -> EsimsResource:
- from .resources.esims import EsimsResource
-
- return EsimsResource(self)
-
@cached_property
def messages(self) -> MessagesResource:
from .resources.messages import MessagesResource
@@ -555,12 +547,6 @@ def notifications(self) -> AsyncNotificationsResource:
return AsyncNotificationsResource(self)
- @cached_property
- def esims(self) -> AsyncEsimsResource:
- from .resources.esims import AsyncEsimsResource
-
- return AsyncEsimsResource(self)
-
@cached_property
def messages(self) -> AsyncMessagesResource:
from .resources.messages import AsyncMessagesResource
@@ -807,12 +793,6 @@ def notifications(self) -> notifications.NotificationsResourceWithRawResponse:
return NotificationsResourceWithRawResponse(self._client.notifications)
- @cached_property
- def esims(self) -> esims.EsimsResourceWithRawResponse:
- from .resources.esims import EsimsResourceWithRawResponse
-
- return EsimsResourceWithRawResponse(self._client.esims)
-
@cached_property
def messages(self) -> messages.MessagesResourceWithRawResponse:
from .resources.messages import MessagesResourceWithRawResponse
@@ -936,12 +916,6 @@ def notifications(self) -> notifications.AsyncNotificationsResourceWithRawRespon
return AsyncNotificationsResourceWithRawResponse(self._client.notifications)
- @cached_property
- def esims(self) -> esims.AsyncEsimsResourceWithRawResponse:
- from .resources.esims import AsyncEsimsResourceWithRawResponse
-
- return AsyncEsimsResourceWithRawResponse(self._client.esims)
-
@cached_property
def messages(self) -> messages.AsyncMessagesResourceWithRawResponse:
from .resources.messages import AsyncMessagesResourceWithRawResponse
@@ -1065,12 +1039,6 @@ def notifications(self) -> notifications.NotificationsResourceWithStreamingRespo
return NotificationsResourceWithStreamingResponse(self._client.notifications)
- @cached_property
- def esims(self) -> esims.EsimsResourceWithStreamingResponse:
- from .resources.esims import EsimsResourceWithStreamingResponse
-
- return EsimsResourceWithStreamingResponse(self._client.esims)
-
@cached_property
def messages(self) -> messages.MessagesResourceWithStreamingResponse:
from .resources.messages import MessagesResourceWithStreamingResponse
@@ -1194,12 +1162,6 @@ def notifications(self) -> notifications.AsyncNotificationsResourceWithStreaming
return AsyncNotificationsResourceWithStreamingResponse(self._client.notifications)
- @cached_property
- def esims(self) -> esims.AsyncEsimsResourceWithStreamingResponse:
- from .resources.esims import AsyncEsimsResourceWithStreamingResponse
-
- return AsyncEsimsResourceWithStreamingResponse(self._client.esims)
-
@cached_property
def messages(self) -> messages.AsyncMessagesResourceWithStreamingResponse:
from .resources.messages import AsyncMessagesResourceWithStreamingResponse
diff --git a/src/mobilerun_sdk/resources/__init__.py b/src/mobilerun_sdk/resources/__init__.py
index c86ce259..30c0dbfc 100644
--- a/src/mobilerun_sdk/resources/__init__.py
+++ b/src/mobilerun_sdk/resources/__init__.py
@@ -8,14 +8,6 @@
AppsResourceWithStreamingResponse,
AsyncAppsResourceWithStreamingResponse,
)
-from .esims import (
- EsimsResource,
- AsyncEsimsResource,
- EsimsResourceWithRawResponse,
- AsyncEsimsResourceWithRawResponse,
- EsimsResourceWithStreamingResponse,
- AsyncEsimsResourceWithStreamingResponse,
-)
from .files import (
FilesResource,
AsyncFilesResource,
@@ -258,12 +250,6 @@
"AsyncNotificationsResourceWithRawResponse",
"NotificationsResourceWithStreamingResponse",
"AsyncNotificationsResourceWithStreamingResponse",
- "EsimsResource",
- "AsyncEsimsResource",
- "EsimsResourceWithRawResponse",
- "AsyncEsimsResourceWithRawResponse",
- "EsimsResourceWithStreamingResponse",
- "AsyncEsimsResourceWithStreamingResponse",
"MessagesResource",
"AsyncMessagesResource",
"MessagesResourceWithRawResponse",
diff --git a/src/mobilerun_sdk/resources/apps.py b/src/mobilerun_sdk/resources/apps.py
index e46dbbf0..3f0f323f 100644
--- a/src/mobilerun_sdk/resources/apps.py
+++ b/src/mobilerun_sdk/resources/apps.py
@@ -183,7 +183,9 @@ def confirm_upload(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AppConfirmUploadResponse:
"""
- Verifies the APK file exists in R2 and sets the app status to available.
+ Verifies the uploaded files in R2 and sets the app version status to available.
+ Idempotent: replaying confirmation for an already-available version returns the
+ same successful response without re-verifying the files.
Args:
extra_headers: Send extra headers
@@ -506,7 +508,9 @@ async def confirm_upload(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AppConfirmUploadResponse:
"""
- Verifies the APK file exists in R2 and sets the app status to available.
+ Verifies the uploaded files in R2 and sets the app version status to available.
+ Idempotent: replaying confirmation for an already-available version returns the
+ same successful response without re-verifying the files.
Args:
extra_headers: Send extra headers
diff --git a/src/mobilerun_sdk/resources/assistant/conversations.py b/src/mobilerun_sdk/resources/assistant/conversations.py
index 04b2a56c..3747f5dd 100644
--- a/src/mobilerun_sdk/resources/assistant/conversations.py
+++ b/src/mobilerun_sdk/resources/assistant/conversations.py
@@ -221,6 +221,7 @@ def abort(
self,
*,
session_id: str,
+ expected_turn_id: str | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -244,7 +245,13 @@ def abort(
"""
return self._post(
"/assistant/chat/abort",
- body=maybe_transform({"session_id": session_id}, conversation_abort_params.ConversationAbortParams),
+ body=maybe_transform(
+ {
+ "session_id": session_id,
+ "expected_turn_id": expected_turn_id,
+ },
+ conversation_abort_params.ConversationAbortParams,
+ ),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -263,8 +270,14 @@ def answer_permission(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> ConversationAnswerPermissionResponse:
- """
- Deliver a HITL approval/rejection for an in-flight turn.
+ """Deliver a HITL approval/rejection for an in-flight turn.
+
+ Interactive HITL
+ clients must start the turn with `Accept: text/event-stream`, wait for a
+ `tool-hitl-approval` event, and send its `permissionId` here at
+ `/assistant/chat/permission`. Do not submit approval as free-form user text or
+ as `confirmed: true`. For `devices.reset`, only `once` and `reject` are allowed;
+ the generic `always` response is rejected with HTTP 400.
Args:
extra_headers: Send extra headers
@@ -428,9 +441,12 @@ def send(
The response format follows the Accept header:
`text/event-stream` for SSE, `application/json` for a buffered assistant reply.
- `sessionId` targets a concrete active chat. The resolved chat session ID is
- returned as `chatSessionId` in the JSON body and as the `X-Chat-Session-Id`
- response header on the SSE response.
+ Interactive HITL requires `Accept: text/event-stream`: the stream can emit a
+ `tool-hitl-approval` event, whose decision must be delivered to
+ `/assistant/chat/permission`. Buffered JSON responses do not provide an
+ interactive HITL continuation contract. `sessionId` targets a concrete active
+ chat. The resolved chat session ID is returned as `chatSessionId` in the JSON
+ body and as the `X-Chat-Session-Id` response header on the SSE response.
Args:
extra_headers: Send extra headers
@@ -677,6 +693,7 @@ async def abort(
self,
*,
session_id: str,
+ expected_turn_id: str | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -701,7 +718,11 @@ async def abort(
return await self._post(
"/assistant/chat/abort",
body=await async_maybe_transform(
- {"session_id": session_id}, conversation_abort_params.ConversationAbortParams
+ {
+ "session_id": session_id,
+ "expected_turn_id": expected_turn_id,
+ },
+ conversation_abort_params.ConversationAbortParams,
),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
@@ -721,8 +742,14 @@ async def answer_permission(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> ConversationAnswerPermissionResponse:
- """
- Deliver a HITL approval/rejection for an in-flight turn.
+ """Deliver a HITL approval/rejection for an in-flight turn.
+
+ Interactive HITL
+ clients must start the turn with `Accept: text/event-stream`, wait for a
+ `tool-hitl-approval` event, and send its `permissionId` here at
+ `/assistant/chat/permission`. Do not submit approval as free-form user text or
+ as `confirmed: true`. For `devices.reset`, only `once` and `reject` are allowed;
+ the generic `always` response is rejected with HTTP 400.
Args:
extra_headers: Send extra headers
@@ -886,9 +913,12 @@ async def send(
The response format follows the Accept header:
`text/event-stream` for SSE, `application/json` for a buffered assistant reply.
- `sessionId` targets a concrete active chat. The resolved chat session ID is
- returned as `chatSessionId` in the JSON body and as the `X-Chat-Session-Id`
- response header on the SSE response.
+ Interactive HITL requires `Accept: text/event-stream`: the stream can emit a
+ `tool-hitl-approval` event, whose decision must be delivered to
+ `/assistant/chat/permission`. Buffered JSON responses do not provide an
+ interactive HITL continuation contract. `sessionId` targets a concrete active
+ chat. The resolved chat session ID is returned as `chatSessionId` in the JSON
+ body and as the `X-Chat-Session-Id` response header on the SSE response.
Args:
extra_headers: Send extra headers
diff --git a/src/mobilerun_sdk/resources/connect/proxies.py b/src/mobilerun_sdk/resources/connect/proxies.py
index c89fce4c..718dc6d6 100644
--- a/src/mobilerun_sdk/resources/connect/proxies.py
+++ b/src/mobilerun_sdk/resources/connect/proxies.py
@@ -9,7 +9,7 @@
import httpx
from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
-from ..._utils import path_template, maybe_transform, async_maybe_transform
+from ..._utils import path_template, maybe_transform, strip_not_given, async_maybe_transform
from ..._compat import cached_property
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import (
@@ -140,6 +140,7 @@ def buy(
*,
country: str,
type: Literal["dedicated_residential", "residential", "mobile"],
+ idempotency_key: str | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -161,6 +162,7 @@ def buy(
timeout: Override the client-level default timeout for this request, in seconds
"""
+ extra_headers = {**strip_not_given({"Idempotency-Key": idempotency_key}), **(extra_headers or {})}
return self._post(
"/connect/proxies",
body=maybe_transform(
@@ -505,6 +507,7 @@ async def buy(
*,
country: str,
type: Literal["dedicated_residential", "residential", "mobile"],
+ idempotency_key: str | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -526,6 +529,7 @@ async def buy(
timeout: Override the client-level default timeout for this request, in seconds
"""
+ extra_headers = {**strip_not_given({"Idempotency-Key": idempotency_key}), **(extra_headers or {})}
return await self._post(
"/connect/proxies",
body=await async_maybe_transform(
diff --git a/src/mobilerun_sdk/resources/devices/apps.py b/src/mobilerun_sdk/resources/devices/apps.py
index f89729c8..e672a017 100644
--- a/src/mobilerun_sdk/resources/devices/apps.py
+++ b/src/mobilerun_sdk/resources/devices/apps.py
@@ -207,7 +207,9 @@ def install(
*,
bundle_id: str,
background: bool | Omit = omit,
+ country: str | Omit = omit,
package_name: str | Omit = omit,
+ version_code: int | Omit = omit,
x_device_display_id: int | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -219,15 +221,16 @@ def install(
"""Requests an app install on the device.
The request body must supply exactly one
- of an Android packageName or an iOS bundleId; protected packages are rejected.
- background (default false) selects the response contract: false installs inline
- and returns the outcome directly (200 on success, an error status on failure);
- true accepts the request and runs the download + install in the background,
- returning 202 immediately — poll list-app-installs for the backend's view of
- that attempt's status. Refuses with 409 once 2 other installs are already
- running on the device, in either mode; a repeat request for an app that already
- has an install running is also refused with 409 rather than superseding it —
- retry once that attempt reaches a terminal state.
+ of an Android packageName or an iOS bundleId; optional country and versionCode
+ select an exact regional uploaded Android version, and protected packages are
+ rejected. background (default false) selects the response contract: false
+ installs inline and returns the outcome directly (200 on success, an error
+ status on failure); true accepts the request and runs the download + install in
+ the background, returning 202 immediately — poll list-app-installs for the
+ backend's view of that attempt's status. Refuses with 409 once 2 other installs
+ are already running on the device, in either mode; a repeat request for an app
+ that already has an install running is also refused with 409 rather than
+ superseding it — retry once that attempt reaches a terminal state.
Args:
bundle_id: iOS bundle identifier (e.g. com.example.app)
@@ -236,8 +239,13 @@ def install(
list-app-installs). false/omitted: install inline and return the outcome
directly (200 on success, an error status on failure).
+ country: Optional ISO 3166-1 alpha-2 country of the uploaded app version (e.g. MY or SG).
+
package_name: Android package name (e.g. com.example.app)
+ version_code: Optional exact app-library version code. Use with country when multiple regional
+ versions share an identifier.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -256,6 +264,8 @@ def install(
package_name: str,
background: bool | Omit = omit,
bundle_id: str | Omit = omit,
+ country: str | Omit = omit,
+ version_code: int | Omit = omit,
x_device_display_id: int | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -267,15 +277,16 @@ def install(
"""Requests an app install on the device.
The request body must supply exactly one
- of an Android packageName or an iOS bundleId; protected packages are rejected.
- background (default false) selects the response contract: false installs inline
- and returns the outcome directly (200 on success, an error status on failure);
- true accepts the request and runs the download + install in the background,
- returning 202 immediately — poll list-app-installs for the backend's view of
- that attempt's status. Refuses with 409 once 2 other installs are already
- running on the device, in either mode; a repeat request for an app that already
- has an install running is also refused with 409 rather than superseding it —
- retry once that attempt reaches a terminal state.
+ of an Android packageName or an iOS bundleId; optional country and versionCode
+ select an exact regional uploaded Android version, and protected packages are
+ rejected. background (default false) selects the response contract: false
+ installs inline and returns the outcome directly (200 on success, an error
+ status on failure); true accepts the request and runs the download + install in
+ the background, returning 202 immediately — poll list-app-installs for the
+ backend's view of that attempt's status. Refuses with 409 once 2 other installs
+ are already running on the device, in either mode; a repeat request for an app
+ that already has an install running is also refused with 409 rather than
+ superseding it — retry once that attempt reaches a terminal state.
Args:
package_name: Android package name (e.g. com.example.app)
@@ -286,6 +297,11 @@ def install(
bundle_id: iOS bundle identifier (e.g. com.example.app)
+ country: Optional ISO 3166-1 alpha-2 country of the uploaded app version (e.g. MY or SG).
+
+ version_code: Optional exact app-library version code. Use with country when multiple regional
+ versions share an identifier.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -303,7 +319,9 @@ def install(
*,
bundle_id: str | Omit = omit,
background: bool | Omit = omit,
+ country: str | Omit = omit,
package_name: str | Omit = omit,
+ version_code: int | Omit = omit,
x_device_display_id: int | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -327,7 +345,9 @@ def install(
{
"bundle_id": bundle_id,
"background": background,
+ "country": country,
"package_name": package_name,
+ "version_code": version_code,
},
app_install_params.AppInstallParams,
),
@@ -350,11 +370,11 @@ def list_installs(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AppListInstallsResponse:
"""
- Reports the backend's view of background app-install attempts on this device —
- status reflects the install ATTEMPT, not device ground truth; list-apps remains
- authoritative for what is actually installed. Records are in-memory and lost on
- service restart; terminal records are kept ~15 minutes. Not gated on device
- readiness, so it also answers while the device is offline or crashed.
+ Reports the backend's durable view of background app-install attempts on this
+ device — status reflects the install ATTEMPT, not device ground truth; list-apps
+ remains authoritative for what is actually installed. Terminal and projected
+ timeout records are kept ~15 minutes. Not gated on device readiness, so it also
+ answers while the device is offline or crashed.
Args:
extra_headers: Send extra headers
@@ -719,7 +739,9 @@ async def install(
*,
bundle_id: str,
background: bool | Omit = omit,
+ country: str | Omit = omit,
package_name: str | Omit = omit,
+ version_code: int | Omit = omit,
x_device_display_id: int | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -731,15 +753,16 @@ async def install(
"""Requests an app install on the device.
The request body must supply exactly one
- of an Android packageName or an iOS bundleId; protected packages are rejected.
- background (default false) selects the response contract: false installs inline
- and returns the outcome directly (200 on success, an error status on failure);
- true accepts the request and runs the download + install in the background,
- returning 202 immediately — poll list-app-installs for the backend's view of
- that attempt's status. Refuses with 409 once 2 other installs are already
- running on the device, in either mode; a repeat request for an app that already
- has an install running is also refused with 409 rather than superseding it —
- retry once that attempt reaches a terminal state.
+ of an Android packageName or an iOS bundleId; optional country and versionCode
+ select an exact regional uploaded Android version, and protected packages are
+ rejected. background (default false) selects the response contract: false
+ installs inline and returns the outcome directly (200 on success, an error
+ status on failure); true accepts the request and runs the download + install in
+ the background, returning 202 immediately — poll list-app-installs for the
+ backend's view of that attempt's status. Refuses with 409 once 2 other installs
+ are already running on the device, in either mode; a repeat request for an app
+ that already has an install running is also refused with 409 rather than
+ superseding it — retry once that attempt reaches a terminal state.
Args:
bundle_id: iOS bundle identifier (e.g. com.example.app)
@@ -748,8 +771,13 @@ async def install(
list-app-installs). false/omitted: install inline and return the outcome
directly (200 on success, an error status on failure).
+ country: Optional ISO 3166-1 alpha-2 country of the uploaded app version (e.g. MY or SG).
+
package_name: Android package name (e.g. com.example.app)
+ version_code: Optional exact app-library version code. Use with country when multiple regional
+ versions share an identifier.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -768,6 +796,8 @@ async def install(
package_name: str,
background: bool | Omit = omit,
bundle_id: str | Omit = omit,
+ country: str | Omit = omit,
+ version_code: int | Omit = omit,
x_device_display_id: int | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -779,15 +809,16 @@ async def install(
"""Requests an app install on the device.
The request body must supply exactly one
- of an Android packageName or an iOS bundleId; protected packages are rejected.
- background (default false) selects the response contract: false installs inline
- and returns the outcome directly (200 on success, an error status on failure);
- true accepts the request and runs the download + install in the background,
- returning 202 immediately — poll list-app-installs for the backend's view of
- that attempt's status. Refuses with 409 once 2 other installs are already
- running on the device, in either mode; a repeat request for an app that already
- has an install running is also refused with 409 rather than superseding it —
- retry once that attempt reaches a terminal state.
+ of an Android packageName or an iOS bundleId; optional country and versionCode
+ select an exact regional uploaded Android version, and protected packages are
+ rejected. background (default false) selects the response contract: false
+ installs inline and returns the outcome directly (200 on success, an error
+ status on failure); true accepts the request and runs the download + install in
+ the background, returning 202 immediately — poll list-app-installs for the
+ backend's view of that attempt's status. Refuses with 409 once 2 other installs
+ are already running on the device, in either mode; a repeat request for an app
+ that already has an install running is also refused with 409 rather than
+ superseding it — retry once that attempt reaches a terminal state.
Args:
package_name: Android package name (e.g. com.example.app)
@@ -798,6 +829,11 @@ async def install(
bundle_id: iOS bundle identifier (e.g. com.example.app)
+ country: Optional ISO 3166-1 alpha-2 country of the uploaded app version (e.g. MY or SG).
+
+ version_code: Optional exact app-library version code. Use with country when multiple regional
+ versions share an identifier.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -815,7 +851,9 @@ async def install(
*,
bundle_id: str | Omit = omit,
background: bool | Omit = omit,
+ country: str | Omit = omit,
package_name: str | Omit = omit,
+ version_code: int | Omit = omit,
x_device_display_id: int | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -839,7 +877,9 @@ async def install(
{
"bundle_id": bundle_id,
"background": background,
+ "country": country,
"package_name": package_name,
+ "version_code": version_code,
},
app_install_params.AppInstallParams,
),
@@ -862,11 +902,11 @@ async def list_installs(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AppListInstallsResponse:
"""
- Reports the backend's view of background app-install attempts on this device —
- status reflects the install ATTEMPT, not device ground truth; list-apps remains
- authoritative for what is actually installed. Records are in-memory and lost on
- service restart; terminal records are kept ~15 minutes. Not gated on device
- readiness, so it also answers while the device is offline or crashed.
+ Reports the backend's durable view of background app-install attempts on this
+ device — status reflects the install ATTEMPT, not device ground truth; list-apps
+ remains authoritative for what is actually installed. Terminal and projected
+ timeout records are kept ~15 minutes. Not gated on device readiness, so it also
+ answers while the device is offline or crashed.
Args:
extra_headers: Send extra headers
diff --git a/src/mobilerun_sdk/resources/devices/devices.py b/src/mobilerun_sdk/resources/devices/devices.py
index ad34958e..a678d943 100644
--- a/src/mobilerun_sdk/resources/devices/devices.py
+++ b/src/mobilerun_sdk/resources/devices/devices.py
@@ -657,10 +657,9 @@ def resume(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> None:
"""
- Wakes a parked device: capacity is preflighted (the device's data may be
- replicated to another node if its home is full), the device starts running
- again, and per-minute billing resumes. On a device that is not parked this is a
- no-op ready transition.
+ Wakes a parked device: backend readiness and any required capacity are
+ preflighted, the same device starts running again, and per-minute billing
+ resumes. On a device that is not parked this is a no-op ready transition.
Args:
extra_headers: Send extra headers
@@ -1344,10 +1343,9 @@ async def resume(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> None:
"""
- Wakes a parked device: capacity is preflighted (the device's data may be
- replicated to another node if its home is full), the device starts running
- again, and per-minute billing resumes. On a device that is not parked this is a
- no-op ready transition.
+ Wakes a parked device: backend readiness and any required capacity are
+ preflighted, the same device starts running again, and per-minute billing
+ resumes. On a device that is not parked this is a no-op ready transition.
Args:
extra_headers: Send extra headers
diff --git a/src/mobilerun_sdk/resources/devices/keyboard.py b/src/mobilerun_sdk/resources/devices/keyboard.py
index a1bd8bbc..dd5439ce 100644
--- a/src/mobilerun_sdk/resources/devices/keyboard.py
+++ b/src/mobilerun_sdk/resources/devices/keyboard.py
@@ -2,6 +2,8 @@
from __future__ import annotations
+from typing_extensions import Literal
+
import httpx
from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
@@ -130,6 +132,7 @@ def write(
*,
text: str,
clear: bool | Omit = omit,
+ completion_mode: Literal["accepted", "committed"] | Omit = omit,
error_rate: float | Omit = omit,
stealth: bool | Omit = omit,
wpm: int | Omit = omit,
@@ -141,13 +144,17 @@ def write(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> None:
- """Types the given text into the focused input field.
+ """Types text into the focused input field.
- Supports optionally clearing
- the field first and a stealth mode that emulates human typing speed and error
- rate on supported devices.
+ The optional completionMode defaults to
+ accepted for backwards-compatible low latency; committed additionally waits for
+ the complete text or a quiescent UI state.
Args:
+ completion_mode: Completion guarantee. accepted returns after the input provider accepts the
+ operation; committed additionally waits for the focused UI state to contain the
+ complete text or become quiescent.
+
error_rate: Per-character mistake rate for humantouch typing. -1 uses server default.
wpm: Words per minute for stealth typing. 0 uses portal default.
@@ -175,6 +182,7 @@ def write(
{
"text": text,
"clear": clear,
+ "completion_mode": completion_mode,
"error_rate": error_rate,
"stealth": stealth,
"wpm": wpm,
@@ -298,6 +306,7 @@ async def write(
*,
text: str,
clear: bool | Omit = omit,
+ completion_mode: Literal["accepted", "committed"] | Omit = omit,
error_rate: float | Omit = omit,
stealth: bool | Omit = omit,
wpm: int | Omit = omit,
@@ -309,13 +318,17 @@ async def write(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> None:
- """Types the given text into the focused input field.
+ """Types text into the focused input field.
- Supports optionally clearing
- the field first and a stealth mode that emulates human typing speed and error
- rate on supported devices.
+ The optional completionMode defaults to
+ accepted for backwards-compatible low latency; committed additionally waits for
+ the complete text or a quiescent UI state.
Args:
+ completion_mode: Completion guarantee. accepted returns after the input provider accepts the
+ operation; committed additionally waits for the focused UI state to contain the
+ complete text or become quiescent.
+
error_rate: Per-character mistake rate for humantouch typing. -1 uses server default.
wpm: Words per minute for stealth typing. 0 uses portal default.
@@ -343,6 +356,7 @@ async def write(
{
"text": text,
"clear": clear,
+ "completion_mode": completion_mode,
"error_rate": error_rate,
"stealth": stealth,
"wpm": wpm,
diff --git a/src/mobilerun_sdk/resources/devices/recordings.py b/src/mobilerun_sdk/resources/devices/recordings.py
index 11ed0b6a..1591a3b8 100644
--- a/src/mobilerun_sdk/resources/devices/recordings.py
+++ b/src/mobilerun_sdk/resources/devices/recordings.py
@@ -135,6 +135,7 @@ def start(
device_id: str,
*,
name: str | Omit = omit,
+ quality: int | Omit = omit,
retention_days: int | Omit = omit,
types: Optional[SequenceNotStr[str]] | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -148,6 +149,14 @@ def start(
Start a device recording
Args:
+ quality: Capture quality from 1 (lowest) to 10 (full stream quality). Defaults to the
+ device's full quality. Honored by devices recording through the portal stream
+ bridge.
+
+ types: Artifacts to capture: trajectory (input actions), video, and audio (captured
+ into the video artifact, so it requires video; honored by portal stream-bridge
+ recorders). Defaults to trajectory and video.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -163,6 +172,7 @@ def start(
body=maybe_transform(
{
"name": name,
+ "quality": quality,
"retention_days": retention_days,
"types": types,
},
@@ -440,6 +450,7 @@ async def start(
device_id: str,
*,
name: str | Omit = omit,
+ quality: int | Omit = omit,
retention_days: int | Omit = omit,
types: Optional[SequenceNotStr[str]] | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -453,6 +464,14 @@ async def start(
Start a device recording
Args:
+ quality: Capture quality from 1 (lowest) to 10 (full stream quality). Defaults to the
+ device's full quality. Honored by devices recording through the portal stream
+ bridge.
+
+ types: Artifacts to capture: trajectory (input actions), video, and audio (captured
+ into the video artifact, so it requires video; honored by portal stream-bridge
+ recorders). Defaults to trajectory and video.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -468,6 +487,7 @@ async def start(
body=await async_maybe_transform(
{
"name": name,
+ "quality": quality,
"retention_days": retention_days,
"types": types,
},
diff --git a/src/mobilerun_sdk/resources/esims/__init__.py b/src/mobilerun_sdk/resources/esims/__init__.py
deleted file mode 100644
index 394c2d72..00000000
--- a/src/mobilerun_sdk/resources/esims/__init__.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from .esims import (
- EsimsResource,
- AsyncEsimsResource,
- EsimsResourceWithRawResponse,
- AsyncEsimsResourceWithRawResponse,
- EsimsResourceWithStreamingResponse,
- AsyncEsimsResourceWithStreamingResponse,
-)
-from .messages import (
- MessagesResource,
- AsyncMessagesResource,
- MessagesResourceWithRawResponse,
- AsyncMessagesResourceWithRawResponse,
- MessagesResourceWithStreamingResponse,
- AsyncMessagesResourceWithStreamingResponse,
-)
-
-__all__ = [
- "MessagesResource",
- "AsyncMessagesResource",
- "MessagesResourceWithRawResponse",
- "AsyncMessagesResourceWithRawResponse",
- "MessagesResourceWithStreamingResponse",
- "AsyncMessagesResourceWithStreamingResponse",
- "EsimsResource",
- "AsyncEsimsResource",
- "EsimsResourceWithRawResponse",
- "AsyncEsimsResourceWithRawResponse",
- "EsimsResourceWithStreamingResponse",
- "AsyncEsimsResourceWithStreamingResponse",
-]
diff --git a/src/mobilerun_sdk/resources/esims/esims.py b/src/mobilerun_sdk/resources/esims/esims.py
deleted file mode 100644
index 49347cbe..00000000
--- a/src/mobilerun_sdk/resources/esims/esims.py
+++ /dev/null
@@ -1,1286 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Optional
-from typing_extensions import Literal
-
-import httpx
-
-from ...types import (
- esim_list_params,
- esim_create_params,
- esim_import_params,
- esim_update_params,
- esim_install_params,
- esim_selector_params,
-)
-from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
-from ..._utils import path_template, maybe_transform, async_maybe_transform
-from .messages import (
- MessagesResource,
- AsyncMessagesResource,
- MessagesResourceWithRawResponse,
- AsyncMessagesResourceWithRawResponse,
- MessagesResourceWithStreamingResponse,
- AsyncMessagesResourceWithStreamingResponse,
-)
-from ..._compat import cached_property
-from ..._resource import SyncAPIResource, AsyncAPIResource
-from ..._response import (
- to_raw_response_wrapper,
- to_streamed_response_wrapper,
- async_to_raw_response_wrapper,
- async_to_streamed_response_wrapper,
-)
-from ..._base_client import make_request_options
-from ...types.esim_list_response import EsimListResponse
-from ...types.esim_create_response import EsimCreateResponse
-from ...types.esim_import_response import EsimImportResponse
-from ...types.esim_update_response import EsimUpdateResponse
-from ...types.esim_install_response import EsimInstallResponse
-from ...types.esim_capacity_response import EsimCapacityResponse
-from ...types.esim_retrieve_response import EsimRetrieveResponse
-from ...types.esim_selector_response import EsimSelectorResponse
-from ...types.esim_install_status_response import EsimInstallStatusResponse
-from ...types.esim_confirm_payment_response import EsimConfirmPaymentResponse
-
-__all__ = ["EsimsResource", "AsyncEsimsResource"]
-
-
-class EsimsResource(SyncAPIResource):
- @cached_property
- def messages(self) -> MessagesResource:
- return MessagesResource(self._client)
-
- @cached_property
- def with_raw_response(self) -> EsimsResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
- """
- return EsimsResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> EsimsResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
- """
- return EsimsResourceWithStreamingResponse(self)
-
- def create(
- self,
- *,
- idempotency_key: str | Omit = omit,
- name: Optional[str] | Omit = omit,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> EsimCreateResponse:
- """
- Purchases a physical eSIM from available inventory for the authenticated owner.
- Returns 409 when no stock is available, or 402 with a billing checkout URL when
- billing capacity is exhausted.
-
- Args:
- idempotency_key: Client-supplied key; replaying the same key returns the original purchase
- instead of buying again
-
- name: Optional user-defined display label — NFC-normalized, up to 15 GRAPHEMES. Omit
- or null for no label.
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- return self._post(
- "/numbers/esims",
- body=maybe_transform(
- {
- "idempotency_key": idempotency_key,
- "name": name,
- },
- esim_create_params.EsimCreateParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=EsimCreateResponse,
- )
-
- def retrieve(
- self,
- id: str,
- *,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> EsimRetrieveResponse:
- """
- Retrieves a single physical eSIM.
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return self._get(
- path_template("/numbers/esims/{id}", id=id),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=EsimRetrieveResponse,
- )
-
- def update(
- self,
- id: str,
- *,
- msisdn: Optional[str] | Omit = omit,
- name: Optional[str] | Omit = omit,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> EsimUpdateResponse:
- """Updates the eSIM's self-reported msisdn and/or display name.
-
- Both fields are
- optional, but the request body itself is required. Omitting a field leaves it
- unchanged; setting it to null or an empty string clears it. `name` is capped at
- 15 characters. Available regardless of the eSIM's current status.
-
- Args:
- msisdn: Self-reported E.164 MSISDN for this eSIM's line. Omit to leave unchanged;
- null/empty clears it. An unverified label — never used for routing.
-
- name: User-defined display label — NFC-normalized, up to 15 GRAPHEMES (not UTF-16 code
- units; an emoji/flag may span several). Omit to leave unchanged;
- null/empty/whitespace-only clears it.
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return self._patch(
- path_template("/numbers/esims/{id}", id=id),
- body=maybe_transform(
- {
- "msisdn": msisdn,
- "name": name,
- },
- esim_update_params.EsimUpdateParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=EsimUpdateResponse,
- )
-
- def list(
- self,
- *,
- mine: Literal["true", "false"] | Omit = omit,
- page: int | Omit = omit,
- page_size: int | Omit = omit,
- status: Literal["all", "in_stock", "owned", "installing", "installed", "install_failed", "retired"]
- | Omit = omit,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> EsimListResponse:
- """
- Lists physical eSIMs owned by the authenticated owner.
-
- Args:
- mine: Only include eSIMs created by the calling actor.
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- return self._get(
- "/numbers/esims",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform(
- {
- "mine": mine,
- "page": page,
- "page_size": page_size,
- "status": status,
- },
- esim_list_params.EsimListParams,
- ),
- ),
- cast_to=EsimListResponse,
- )
-
- def delete(
- self,
- id: str,
- *,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> None:
- """Removes a physical eSIM.
-
- Idempotent — returns 204 for a fresh removal or a
- replay of an already-removed eSIM. An eSIM currently installed on a device is
- uninstalled first, then removed. An eSIM in an intermediate install state
- returns 409 `operator_resolution_required` and requires manual resolution.
- Returns 404 if the eSIM doesn't exist or isn't owned by the caller.
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- return self._delete(
- path_template("/numbers/esims/{id}", id=id),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
- def capacity(
- self,
- *,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> EsimCapacityResponse:
- """
- Reports whether a free device is currently available, for pre-checking the
- import flow before upload. This is a hint only, not a reservation —
- `POST /esims/import` re-checks availability at submit time.
- """
- return self._get(
- "/numbers/esims/capacity",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=EsimCapacityResponse,
- )
-
- def confirm_payment(
- self,
- id: str,
- *,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> EsimConfirmPaymentResponse:
- """
- Checks for proof of payment for this eSIM's current rent and confirms it if
- found. If no proof is available yet, returns 200 with the eSIM unchanged rather
- than an error. Always returns the current eSIM state.
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return self._post(
- path_template("/numbers/esims/{id}/confirm-payment", id=id),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=EsimConfirmPaymentResponse,
- )
-
- def import_(
- self,
- *,
- auto_install: bool | Omit = omit,
- carrier_name: str | Omit = omit,
- confirmation_code: str | Omit = omit,
- country_code: str | Omit = omit,
- device_id: str | Omit = omit,
- idempotency_key: str | Omit = omit,
- lpa_code: str | Omit = omit,
- matching_id: str | Omit = omit,
- msisdn: str | Omit = omit,
- name: Optional[str] | Omit = omit,
- notes: str | Omit = omit,
- smdp_address: str | Omit = omit,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> EsimImportResponse:
- """
- Registers a bring-your-own (BYO) eSIM activation code as owned inventory.
- Provide either `{ smdpAddress, matchingId?, confirmationCode? }` or
- `{ lpaCode }` — supplying both, or neither, returns 400. An optional `name` sets
- a display label on the created eSIM (up to 15 characters).
-
- Subject to per-owner and daily import limits, and disabled entirely unless BYO
- imports are enabled for this deployment (409 `byo_disabled`). Idempotent via
- `idempotencyKey`: replaying the same key with an identical request returns the
- original response; the same key with a different request returns 409
- `idempotency_conflict`.
-
- When rent-first billing is off (default), the import is free — 201 with the
- eSIM. Setting `autoInstall: true` additionally dispatches an install immediately
- after import (`deviceId` may only be set together with `autoInstall`): this
- returns 202 with `{esim, operationId, statusUrl}` when the install claim
- succeeds (poll `GET /esims/{id}/install-status`), or 201 with the eSIM plus
- `installDispatch: {ok: false, reason}` when the install could not be dispatched
- — the import itself still succeeds either way.
-
- When rent-first billing is on, import additionally requires available device
- capacity (409 `device_pool_empty`) and is subject to a per-owner
- awaiting-payment cap (409 `byo_awaiting_payment_cap`). On success the eSIM is
- created `awaiting_payment` and a checkout is started: 201 with
- `{esim, rentStatus, checkoutUrl}` when the checkout URL is ready immediately, or
- 202 with `checkoutUrl: null` otherwise — poll `GET /esims/{id}` until it's
- populated. Once payment is confirmed, install is triggered automatically.
-
- Args:
- auto_install: Rent OFF only: dispatch install-on-device immediately after a successful import.
- No-op when ESIM_BYO_RENT_ENABLED=true.
-
- device_id: physedge device id to auto-install onto; requires autoInstall:true and rent OFF.
- Omit for a random pool device.
-
- idempotency_key: Client-supplied key; replaying the same key+request returns the original import
- instead of importing again
-
- lpa_code: Full LPA activation code
-
- msisdn: Self-reported E.164 MSISDN for this eSIM's line — an unverified label, never
- used for routing
-
- name: User-defined display label — NFC-normalized, up to 15 GRAPHEMES (not UTF-16 code
- units; an emoji/flag may span several). Omit/null/empty/whitespace-only leaves
- it unset.
-
- smdp_address: SM-DP+ activation host — bare hostname ONLY, no port/scheme/path.
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- return self._post(
- "/numbers/esims/import",
- body=maybe_transform(
- {
- "auto_install": auto_install,
- "carrier_name": carrier_name,
- "confirmation_code": confirmation_code,
- "country_code": country_code,
- "device_id": device_id,
- "idempotency_key": idempotency_key,
- "lpa_code": lpa_code,
- "matching_id": matching_id,
- "msisdn": msisdn,
- "name": name,
- "notes": notes,
- "smdp_address": smdp_address,
- },
- esim_import_params.EsimImportParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=EsimImportResponse,
- )
-
- def install(
- self,
- id: str,
- *,
- device_id: str | Omit = omit,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> EsimInstallResponse:
- """Installs the eSIM's activation code onto a device.
-
- `deviceId` is optional — omit
- it to use an available device from the pool. This call is asynchronous: it
- returns 202 with `{esim, operationId, statusUrl}` immediately, and the result is
- available by polling `GET /esims/{id}/install-status`. Retrying with the same
- request is safe if a response is lost.
-
- Returns 409 when the eSIM is not in the `owned` state, or when no device is
- currently available (see `reason`). When rent-first billing is enabled, a BYO
- eSIM whose rent isn't active returns 402 with `{esim, rentStatus, checkoutUrl}`
- instead.
-
- Args:
- device_id: physedge device id to install the eSIM onto; omit for a random pool device
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return self._post(
- path_template("/numbers/esims/{id}/install", id=id),
- body=maybe_transform({"device_id": device_id}, esim_install_params.EsimInstallParams),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=EsimInstallResponse,
- )
-
- def install_status(
- self,
- id: str,
- *,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> EsimInstallStatusResponse:
- """
- Returns the eSIM's current install status, checking for a terminal outcome if an
- install is still in progress.
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return self._get(
- path_template("/numbers/esims/{id}/install-status", id=id),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=EsimInstallStatusResponse,
- )
-
- def selector(
- self,
- *,
- page: int | Omit = omit,
- page_size: int | Omit = omit,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> EsimSelectorResponse:
- """
- Returns a lightweight list (id, msisdn, carrierName, status, masked iccid) for
- use in a message filter dropdown. Unlike `GET /esims`, this includes all
- statuses, including retired eSIMs.
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- return self._get(
- "/numbers/esims/selector",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform(
- {
- "page": page,
- "page_size": page_size,
- },
- esim_selector_params.EsimSelectorParams,
- ),
- ),
- cast_to=EsimSelectorResponse,
- )
-
-
-class AsyncEsimsResource(AsyncAPIResource):
- @cached_property
- def messages(self) -> AsyncMessagesResource:
- return AsyncMessagesResource(self._client)
-
- @cached_property
- def with_raw_response(self) -> AsyncEsimsResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
- """
- return AsyncEsimsResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> AsyncEsimsResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
- """
- return AsyncEsimsResourceWithStreamingResponse(self)
-
- async def create(
- self,
- *,
- idempotency_key: str | Omit = omit,
- name: Optional[str] | Omit = omit,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> EsimCreateResponse:
- """
- Purchases a physical eSIM from available inventory for the authenticated owner.
- Returns 409 when no stock is available, or 402 with a billing checkout URL when
- billing capacity is exhausted.
-
- Args:
- idempotency_key: Client-supplied key; replaying the same key returns the original purchase
- instead of buying again
-
- name: Optional user-defined display label — NFC-normalized, up to 15 GRAPHEMES. Omit
- or null for no label.
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- return await self._post(
- "/numbers/esims",
- body=await async_maybe_transform(
- {
- "idempotency_key": idempotency_key,
- "name": name,
- },
- esim_create_params.EsimCreateParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=EsimCreateResponse,
- )
-
- async def retrieve(
- self,
- id: str,
- *,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> EsimRetrieveResponse:
- """
- Retrieves a single physical eSIM.
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return await self._get(
- path_template("/numbers/esims/{id}", id=id),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=EsimRetrieveResponse,
- )
-
- async def update(
- self,
- id: str,
- *,
- msisdn: Optional[str] | Omit = omit,
- name: Optional[str] | Omit = omit,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> EsimUpdateResponse:
- """Updates the eSIM's self-reported msisdn and/or display name.
-
- Both fields are
- optional, but the request body itself is required. Omitting a field leaves it
- unchanged; setting it to null or an empty string clears it. `name` is capped at
- 15 characters. Available regardless of the eSIM's current status.
-
- Args:
- msisdn: Self-reported E.164 MSISDN for this eSIM's line. Omit to leave unchanged;
- null/empty clears it. An unverified label — never used for routing.
-
- name: User-defined display label — NFC-normalized, up to 15 GRAPHEMES (not UTF-16 code
- units; an emoji/flag may span several). Omit to leave unchanged;
- null/empty/whitespace-only clears it.
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return await self._patch(
- path_template("/numbers/esims/{id}", id=id),
- body=await async_maybe_transform(
- {
- "msisdn": msisdn,
- "name": name,
- },
- esim_update_params.EsimUpdateParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=EsimUpdateResponse,
- )
-
- async def list(
- self,
- *,
- mine: Literal["true", "false"] | Omit = omit,
- page: int | Omit = omit,
- page_size: int | Omit = omit,
- status: Literal["all", "in_stock", "owned", "installing", "installed", "install_failed", "retired"]
- | Omit = omit,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> EsimListResponse:
- """
- Lists physical eSIMs owned by the authenticated owner.
-
- Args:
- mine: Only include eSIMs created by the calling actor.
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- return await self._get(
- "/numbers/esims",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform(
- {
- "mine": mine,
- "page": page,
- "page_size": page_size,
- "status": status,
- },
- esim_list_params.EsimListParams,
- ),
- ),
- cast_to=EsimListResponse,
- )
-
- async def delete(
- self,
- id: str,
- *,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> None:
- """Removes a physical eSIM.
-
- Idempotent — returns 204 for a fresh removal or a
- replay of an already-removed eSIM. An eSIM currently installed on a device is
- uninstalled first, then removed. An eSIM in an intermediate install state
- returns 409 `operator_resolution_required` and requires manual resolution.
- Returns 404 if the eSIM doesn't exist or isn't owned by the caller.
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- return await self._delete(
- path_template("/numbers/esims/{id}", id=id),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
- async def capacity(
- self,
- *,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> EsimCapacityResponse:
- """
- Reports whether a free device is currently available, for pre-checking the
- import flow before upload. This is a hint only, not a reservation —
- `POST /esims/import` re-checks availability at submit time.
- """
- return await self._get(
- "/numbers/esims/capacity",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=EsimCapacityResponse,
- )
-
- async def confirm_payment(
- self,
- id: str,
- *,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> EsimConfirmPaymentResponse:
- """
- Checks for proof of payment for this eSIM's current rent and confirms it if
- found. If no proof is available yet, returns 200 with the eSIM unchanged rather
- than an error. Always returns the current eSIM state.
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return await self._post(
- path_template("/numbers/esims/{id}/confirm-payment", id=id),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=EsimConfirmPaymentResponse,
- )
-
- async def import_(
- self,
- *,
- auto_install: bool | Omit = omit,
- carrier_name: str | Omit = omit,
- confirmation_code: str | Omit = omit,
- country_code: str | Omit = omit,
- device_id: str | Omit = omit,
- idempotency_key: str | Omit = omit,
- lpa_code: str | Omit = omit,
- matching_id: str | Omit = omit,
- msisdn: str | Omit = omit,
- name: Optional[str] | Omit = omit,
- notes: str | Omit = omit,
- smdp_address: str | Omit = omit,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> EsimImportResponse:
- """
- Registers a bring-your-own (BYO) eSIM activation code as owned inventory.
- Provide either `{ smdpAddress, matchingId?, confirmationCode? }` or
- `{ lpaCode }` — supplying both, or neither, returns 400. An optional `name` sets
- a display label on the created eSIM (up to 15 characters).
-
- Subject to per-owner and daily import limits, and disabled entirely unless BYO
- imports are enabled for this deployment (409 `byo_disabled`). Idempotent via
- `idempotencyKey`: replaying the same key with an identical request returns the
- original response; the same key with a different request returns 409
- `idempotency_conflict`.
-
- When rent-first billing is off (default), the import is free — 201 with the
- eSIM. Setting `autoInstall: true` additionally dispatches an install immediately
- after import (`deviceId` may only be set together with `autoInstall`): this
- returns 202 with `{esim, operationId, statusUrl}` when the install claim
- succeeds (poll `GET /esims/{id}/install-status`), or 201 with the eSIM plus
- `installDispatch: {ok: false, reason}` when the install could not be dispatched
- — the import itself still succeeds either way.
-
- When rent-first billing is on, import additionally requires available device
- capacity (409 `device_pool_empty`) and is subject to a per-owner
- awaiting-payment cap (409 `byo_awaiting_payment_cap`). On success the eSIM is
- created `awaiting_payment` and a checkout is started: 201 with
- `{esim, rentStatus, checkoutUrl}` when the checkout URL is ready immediately, or
- 202 with `checkoutUrl: null` otherwise — poll `GET /esims/{id}` until it's
- populated. Once payment is confirmed, install is triggered automatically.
-
- Args:
- auto_install: Rent OFF only: dispatch install-on-device immediately after a successful import.
- No-op when ESIM_BYO_RENT_ENABLED=true.
-
- device_id: physedge device id to auto-install onto; requires autoInstall:true and rent OFF.
- Omit for a random pool device.
-
- idempotency_key: Client-supplied key; replaying the same key+request returns the original import
- instead of importing again
-
- lpa_code: Full LPA activation code
-
- msisdn: Self-reported E.164 MSISDN for this eSIM's line — an unverified label, never
- used for routing
-
- name: User-defined display label — NFC-normalized, up to 15 GRAPHEMES (not UTF-16 code
- units; an emoji/flag may span several). Omit/null/empty/whitespace-only leaves
- it unset.
-
- smdp_address: SM-DP+ activation host — bare hostname ONLY, no port/scheme/path.
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- return await self._post(
- "/numbers/esims/import",
- body=await async_maybe_transform(
- {
- "auto_install": auto_install,
- "carrier_name": carrier_name,
- "confirmation_code": confirmation_code,
- "country_code": country_code,
- "device_id": device_id,
- "idempotency_key": idempotency_key,
- "lpa_code": lpa_code,
- "matching_id": matching_id,
- "msisdn": msisdn,
- "name": name,
- "notes": notes,
- "smdp_address": smdp_address,
- },
- esim_import_params.EsimImportParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=EsimImportResponse,
- )
-
- async def install(
- self,
- id: str,
- *,
- device_id: str | Omit = omit,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> EsimInstallResponse:
- """Installs the eSIM's activation code onto a device.
-
- `deviceId` is optional — omit
- it to use an available device from the pool. This call is asynchronous: it
- returns 202 with `{esim, operationId, statusUrl}` immediately, and the result is
- available by polling `GET /esims/{id}/install-status`. Retrying with the same
- request is safe if a response is lost.
-
- Returns 409 when the eSIM is not in the `owned` state, or when no device is
- currently available (see `reason`). When rent-first billing is enabled, a BYO
- eSIM whose rent isn't active returns 402 with `{esim, rentStatus, checkoutUrl}`
- instead.
-
- Args:
- device_id: physedge device id to install the eSIM onto; omit for a random pool device
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return await self._post(
- path_template("/numbers/esims/{id}/install", id=id),
- body=await async_maybe_transform({"device_id": device_id}, esim_install_params.EsimInstallParams),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=EsimInstallResponse,
- )
-
- async def install_status(
- self,
- id: str,
- *,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> EsimInstallStatusResponse:
- """
- Returns the eSIM's current install status, checking for a terminal outcome if an
- install is still in progress.
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return await self._get(
- path_template("/numbers/esims/{id}/install-status", id=id),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=EsimInstallStatusResponse,
- )
-
- async def selector(
- self,
- *,
- page: int | Omit = omit,
- page_size: int | Omit = omit,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> EsimSelectorResponse:
- """
- Returns a lightweight list (id, msisdn, carrierName, status, masked iccid) for
- use in a message filter dropdown. Unlike `GET /esims`, this includes all
- statuses, including retired eSIMs.
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- return await self._get(
- "/numbers/esims/selector",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform(
- {
- "page": page,
- "page_size": page_size,
- },
- esim_selector_params.EsimSelectorParams,
- ),
- ),
- cast_to=EsimSelectorResponse,
- )
-
-
-class EsimsResourceWithRawResponse:
- def __init__(self, esims: EsimsResource) -> None:
- self._esims = esims
-
- self.create = to_raw_response_wrapper(
- esims.create,
- )
- self.retrieve = to_raw_response_wrapper(
- esims.retrieve,
- )
- self.update = to_raw_response_wrapper(
- esims.update,
- )
- self.list = to_raw_response_wrapper(
- esims.list,
- )
- self.delete = to_raw_response_wrapper(
- esims.delete,
- )
- self.capacity = to_raw_response_wrapper(
- esims.capacity,
- )
- self.confirm_payment = to_raw_response_wrapper(
- esims.confirm_payment,
- )
- self.import_ = to_raw_response_wrapper(
- esims.import_,
- )
- self.install = to_raw_response_wrapper(
- esims.install,
- )
- self.install_status = to_raw_response_wrapper(
- esims.install_status,
- )
- self.selector = to_raw_response_wrapper(
- esims.selector,
- )
-
- @cached_property
- def messages(self) -> MessagesResourceWithRawResponse:
- return MessagesResourceWithRawResponse(self._esims.messages)
-
-
-class AsyncEsimsResourceWithRawResponse:
- def __init__(self, esims: AsyncEsimsResource) -> None:
- self._esims = esims
-
- self.create = async_to_raw_response_wrapper(
- esims.create,
- )
- self.retrieve = async_to_raw_response_wrapper(
- esims.retrieve,
- )
- self.update = async_to_raw_response_wrapper(
- esims.update,
- )
- self.list = async_to_raw_response_wrapper(
- esims.list,
- )
- self.delete = async_to_raw_response_wrapper(
- esims.delete,
- )
- self.capacity = async_to_raw_response_wrapper(
- esims.capacity,
- )
- self.confirm_payment = async_to_raw_response_wrapper(
- esims.confirm_payment,
- )
- self.import_ = async_to_raw_response_wrapper(
- esims.import_,
- )
- self.install = async_to_raw_response_wrapper(
- esims.install,
- )
- self.install_status = async_to_raw_response_wrapper(
- esims.install_status,
- )
- self.selector = async_to_raw_response_wrapper(
- esims.selector,
- )
-
- @cached_property
- def messages(self) -> AsyncMessagesResourceWithRawResponse:
- return AsyncMessagesResourceWithRawResponse(self._esims.messages)
-
-
-class EsimsResourceWithStreamingResponse:
- def __init__(self, esims: EsimsResource) -> None:
- self._esims = esims
-
- self.create = to_streamed_response_wrapper(
- esims.create,
- )
- self.retrieve = to_streamed_response_wrapper(
- esims.retrieve,
- )
- self.update = to_streamed_response_wrapper(
- esims.update,
- )
- self.list = to_streamed_response_wrapper(
- esims.list,
- )
- self.delete = to_streamed_response_wrapper(
- esims.delete,
- )
- self.capacity = to_streamed_response_wrapper(
- esims.capacity,
- )
- self.confirm_payment = to_streamed_response_wrapper(
- esims.confirm_payment,
- )
- self.import_ = to_streamed_response_wrapper(
- esims.import_,
- )
- self.install = to_streamed_response_wrapper(
- esims.install,
- )
- self.install_status = to_streamed_response_wrapper(
- esims.install_status,
- )
- self.selector = to_streamed_response_wrapper(
- esims.selector,
- )
-
- @cached_property
- def messages(self) -> MessagesResourceWithStreamingResponse:
- return MessagesResourceWithStreamingResponse(self._esims.messages)
-
-
-class AsyncEsimsResourceWithStreamingResponse:
- def __init__(self, esims: AsyncEsimsResource) -> None:
- self._esims = esims
-
- self.create = async_to_streamed_response_wrapper(
- esims.create,
- )
- self.retrieve = async_to_streamed_response_wrapper(
- esims.retrieve,
- )
- self.update = async_to_streamed_response_wrapper(
- esims.update,
- )
- self.list = async_to_streamed_response_wrapper(
- esims.list,
- )
- self.delete = async_to_streamed_response_wrapper(
- esims.delete,
- )
- self.capacity = async_to_streamed_response_wrapper(
- esims.capacity,
- )
- self.confirm_payment = async_to_streamed_response_wrapper(
- esims.confirm_payment,
- )
- self.import_ = async_to_streamed_response_wrapper(
- esims.import_,
- )
- self.install = async_to_streamed_response_wrapper(
- esims.install,
- )
- self.install_status = async_to_streamed_response_wrapper(
- esims.install_status,
- )
- self.selector = async_to_streamed_response_wrapper(
- esims.selector,
- )
-
- @cached_property
- def messages(self) -> AsyncMessagesResourceWithStreamingResponse:
- return AsyncMessagesResourceWithStreamingResponse(self._esims.messages)
diff --git a/src/mobilerun_sdk/resources/esims/messages.py b/src/mobilerun_sdk/resources/esims/messages.py
deleted file mode 100644
index f6d7efad..00000000
--- a/src/mobilerun_sdk/resources/esims/messages.py
+++ /dev/null
@@ -1,352 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Literal
-
-import httpx
-
-from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from ..._utils import path_template, maybe_transform, async_maybe_transform
-from ..._compat import cached_property
-from ..._resource import SyncAPIResource, AsyncAPIResource
-from ..._response import (
- to_raw_response_wrapper,
- to_streamed_response_wrapper,
- async_to_raw_response_wrapper,
- async_to_streamed_response_wrapper,
-)
-from ...types.esims import message_list_params, message_send_params
-from ..._base_client import make_request_options
-from ...types.esims.message_list_response import MessageListResponse
-from ...types.esims.message_send_response import MessageSendResponse
-
-__all__ = ["MessagesResource", "AsyncMessagesResource"]
-
-
-class MessagesResource(SyncAPIResource):
- @cached_property
- def with_raw_response(self) -> MessagesResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
- """
- return MessagesResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> MessagesResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
- """
- return MessagesResourceWithStreamingResponse(self)
-
- def list(
- self,
- id: str,
- *,
- direction: Literal["all", "inbound", "outbound"] | Omit = omit,
- number_id: str | Omit = omit,
- page: int | Omit = omit,
- page_size: int | Omit = omit,
- peer_key: str | Omit = omit,
- peer_number: str | Omit = omit,
- status: Literal[
- "all", "received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed"
- ]
- | Omit = omit,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> MessageListResponse:
- """
- List messages for one eSIM
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return self._get(
- path_template("/numbers/esims/{id}/messages", id=id),
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform(
- {
- "direction": direction,
- "number_id": number_id,
- "page": page,
- "page_size": page_size,
- "peer_key": peer_key,
- "peer_number": peer_number,
- "status": status,
- },
- message_list_params.MessageListParams,
- ),
- ),
- cast_to=MessageListResponse,
- )
-
- def send(
- self,
- id: str,
- *,
- body: str,
- to: str,
- client_request_id: str | Omit = omit,
- delivery_report: bool | Omit = omit,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> MessageSendResponse:
- """
- Send an SMS through one eSIM
-
- Args:
- body: SMS body text (max 320 chars — smaller than the admin tier's cap; see the
- schema's own doc comment for why)
-
- to: Recipient phone number — normalized to E.164 (spaces/dashes/dots stripped);
- rejected with 400 if it doesn't validate as E.164 afterward.
-
- client_request_id: Client-supplied idempotency key, scoped to (owner, esimId, key). Replaying the
- same key + identical payload returns the original send; the same key with a
- DIFFERENT payload is a 409 conflict.
-
- delivery_report: Wait for physedge to confirm carrier delivery before completing the send (adds
- executor-side latency, never on this request — sends are always async/202).
- Defaults to false for the public tier (opt-in, unlike the admin tier's
- default-true).
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return self._post(
- path_template("/numbers/esims/{id}/messages", id=id),
- body=maybe_transform(
- {
- "body": body,
- "to": to,
- "client_request_id": client_request_id,
- "delivery_report": delivery_report,
- },
- message_send_params.MessageSendParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=MessageSendResponse,
- )
-
-
-class AsyncMessagesResource(AsyncAPIResource):
- @cached_property
- def with_raw_response(self) -> AsyncMessagesResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
- """
- return AsyncMessagesResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> AsyncMessagesResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
- """
- return AsyncMessagesResourceWithStreamingResponse(self)
-
- async def list(
- self,
- id: str,
- *,
- direction: Literal["all", "inbound", "outbound"] | Omit = omit,
- number_id: str | Omit = omit,
- page: int | Omit = omit,
- page_size: int | Omit = omit,
- peer_key: str | Omit = omit,
- peer_number: str | Omit = omit,
- status: Literal[
- "all", "received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed"
- ]
- | Omit = omit,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> MessageListResponse:
- """
- List messages for one eSIM
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return await self._get(
- path_template("/numbers/esims/{id}/messages", id=id),
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform(
- {
- "direction": direction,
- "number_id": number_id,
- "page": page,
- "page_size": page_size,
- "peer_key": peer_key,
- "peer_number": peer_number,
- "status": status,
- },
- message_list_params.MessageListParams,
- ),
- ),
- cast_to=MessageListResponse,
- )
-
- async def send(
- self,
- id: str,
- *,
- body: str,
- to: str,
- client_request_id: str | Omit = omit,
- delivery_report: bool | Omit = omit,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> MessageSendResponse:
- """
- Send an SMS through one eSIM
-
- Args:
- body: SMS body text (max 320 chars — smaller than the admin tier's cap; see the
- schema's own doc comment for why)
-
- to: Recipient phone number — normalized to E.164 (spaces/dashes/dots stripped);
- rejected with 400 if it doesn't validate as E.164 afterward.
-
- client_request_id: Client-supplied idempotency key, scoped to (owner, esimId, key). Replaying the
- same key + identical payload returns the original send; the same key with a
- DIFFERENT payload is a 409 conflict.
-
- delivery_report: Wait for physedge to confirm carrier delivery before completing the send (adds
- executor-side latency, never on this request — sends are always async/202).
- Defaults to false for the public tier (opt-in, unlike the admin tier's
- default-true).
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not id:
- raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
- return await self._post(
- path_template("/numbers/esims/{id}/messages", id=id),
- body=await async_maybe_transform(
- {
- "body": body,
- "to": to,
- "client_request_id": client_request_id,
- "delivery_report": delivery_report,
- },
- message_send_params.MessageSendParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=MessageSendResponse,
- )
-
-
-class MessagesResourceWithRawResponse:
- def __init__(self, messages: MessagesResource) -> None:
- self._messages = messages
-
- self.list = to_raw_response_wrapper(
- messages.list,
- )
- self.send = to_raw_response_wrapper(
- messages.send,
- )
-
-
-class AsyncMessagesResourceWithRawResponse:
- def __init__(self, messages: AsyncMessagesResource) -> None:
- self._messages = messages
-
- self.list = async_to_raw_response_wrapper(
- messages.list,
- )
- self.send = async_to_raw_response_wrapper(
- messages.send,
- )
-
-
-class MessagesResourceWithStreamingResponse:
- def __init__(self, messages: MessagesResource) -> None:
- self._messages = messages
-
- self.list = to_streamed_response_wrapper(
- messages.list,
- )
- self.send = to_streamed_response_wrapper(
- messages.send,
- )
-
-
-class AsyncMessagesResourceWithStreamingResponse:
- def __init__(self, messages: AsyncMessagesResource) -> None:
- self._messages = messages
-
- self.list = async_to_streamed_response_wrapper(
- messages.list,
- )
- self.send = async_to_streamed_response_wrapper(
- messages.send,
- )
diff --git a/src/mobilerun_sdk/resources/mailboxes/mailboxes.py b/src/mobilerun_sdk/resources/mailboxes/mailboxes.py
index 0a62f3c9..50e03570 100644
--- a/src/mobilerun_sdk/resources/mailboxes/mailboxes.py
+++ b/src/mobilerun_sdk/resources/mailboxes/mailboxes.py
@@ -75,7 +75,8 @@ def create(
self,
*,
client_request_id: str,
- billing_preference: Literal["included", "rent"] | Omit = omit,
+ billing_preference: Literal["included", "included_only", "rent"] | Omit = omit,
+ domain_id: str | Omit = omit,
label: str | Omit = omit,
local_part: str | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -85,22 +86,22 @@ def create(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> MailboxCreateResponse:
- """
- Reserves a permanently-allocated, individually-rented mailbox and starts an
- Autumn rental checkout. An optional localPart selects the full address local
- part; omitting it keeps the default random, non-guessable mx\\__-prefixed address.
- The address is withheld until the first payment is confirmed. Idempotent on
- (owner, clientRequestId): same key + payload replays (200); a conflicting or
- already-held local part returns 409. 201 when the checkout URL is already
- persisted, otherwise 202 (poll GET for the URL).
+ """Creates a mailbox on the default domain or a connected custom domain.
+
+ An
+ optional `localPart` selects the address. Replaying the same `clientRequestId`
+ and payload returns the original mailbox. Poll the mailbox when a 202 response
+ does not yet include a checkout URL.
Args:
- billing_preference: Funding preference. Omit or use included for included-first activation; rent
- always preserves package capacity and starts paid checkout.
+ billing_preference: included uses package capacity when available and otherwise starts paid
+ checkout; included_only fails without creating a paid reservation when no
+ included slot remains; rent always starts paid checkout.
+
+ domain_id: Optional active custom mailbox domain owned by the caller. Omit to use the
+ system domain.
- local_part: Optional full mailbox local part (the address before "@"). Trimmed and
- lowercased before validation. Omit for a random, non-guessable mx\\__-prefixed
- address.
+ local_part: Optional mailbox name before the "@". Omit to generate a random address.
extra_headers: Send extra headers
@@ -116,6 +117,7 @@ def create(
{
"client_request_id": client_request_id,
"billing_preference": billing_preference,
+ "domain_id": domain_id,
"label": label,
"local_part": local_part,
},
@@ -248,12 +250,9 @@ def delete(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> MailboxDeleteResponse:
- """For paid rent, schedules end-of-cycle cancellation.
-
- For an included generation,
- archives immediately and releases its package seat. This never deletes the
- mailbox, its address, or its messages — the address is permanently reserved.
- Idempotent.
+ """
+ Cancels a pending mailbox or schedules an active paid mailbox for cancellation.
+ Existing addresses and messages are retained. Repeating the request is safe.
Args:
extra_headers: Send extra headers
@@ -284,10 +283,7 @@ def capacity(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> MailboxCapacityResponse:
- """
- Returns the authoritative number of package-funded mailbox claims currently
- available after local reservations.
- """
+ """Returns the number of mailboxes currently available through included capacity."""
return self._get(
"/mailboxes/capacity",
options=make_request_options(
@@ -311,10 +307,10 @@ def otp(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> MailboxOtpResponse:
- """
- Returns the highest-confidence, most recent OTP for the mailbox, restricted to
- messages of completed/active paid intervals. Does not wait server-side (SDKs
- poll). 200 with the best code, 204 when none matches.
+ """Returns the most likely recent OTP for the mailbox.
+
+ Returns 204 when no matching
+ code is available.
Args:
extra_headers: Send extra headers
@@ -351,7 +347,7 @@ def restart(
self,
mailbox_id: str,
*,
- billing_preference: Literal["included", "rent"] | Omit = omit,
+ billing_preference: Literal["included", "included_only", "rent"] | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -359,13 +355,15 @@ def restart(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> MailboxRestartResponse:
- """
- Starts a new generation on an archived mailbox, reusing the same permanent
- address. Uses included capacity first unless paid rent is requested.
+ """Restarts an archived mailbox with the same address.
+
+ Uses included capacity when
+ available unless paid service is requested.
Args:
- billing_preference: Funding preference. Omit or use included for included-first activation; rent
- always preserves package capacity and starts paid checkout.
+ billing_preference: included uses package capacity when available and otherwise starts paid
+ checkout; included_only fails without creating a paid reservation when no
+ included slot remains; rent always starts paid checkout.
extra_headers: Send extra headers
@@ -399,10 +397,10 @@ def uncancel(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> MailboxUncancelResponse:
- """Retracts a scheduled end-of-cycle cancellation for the current generation.
+ """Withdraws a scheduled cancellation.
- Only
- valid while cancellation is pending.
+ Only available while cancellation is
+ pending.
Args:
extra_headers: Send extra headers
@@ -452,7 +450,8 @@ async def create(
self,
*,
client_request_id: str,
- billing_preference: Literal["included", "rent"] | Omit = omit,
+ billing_preference: Literal["included", "included_only", "rent"] | Omit = omit,
+ domain_id: str | Omit = omit,
label: str | Omit = omit,
local_part: str | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -462,22 +461,22 @@ async def create(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> MailboxCreateResponse:
- """
- Reserves a permanently-allocated, individually-rented mailbox and starts an
- Autumn rental checkout. An optional localPart selects the full address local
- part; omitting it keeps the default random, non-guessable mx\\__-prefixed address.
- The address is withheld until the first payment is confirmed. Idempotent on
- (owner, clientRequestId): same key + payload replays (200); a conflicting or
- already-held local part returns 409. 201 when the checkout URL is already
- persisted, otherwise 202 (poll GET for the URL).
+ """Creates a mailbox on the default domain or a connected custom domain.
+
+ An
+ optional `localPart` selects the address. Replaying the same `clientRequestId`
+ and payload returns the original mailbox. Poll the mailbox when a 202 response
+ does not yet include a checkout URL.
Args:
- billing_preference: Funding preference. Omit or use included for included-first activation; rent
- always preserves package capacity and starts paid checkout.
+ billing_preference: included uses package capacity when available and otherwise starts paid
+ checkout; included_only fails without creating a paid reservation when no
+ included slot remains; rent always starts paid checkout.
+
+ domain_id: Optional active custom mailbox domain owned by the caller. Omit to use the
+ system domain.
- local_part: Optional full mailbox local part (the address before "@"). Trimmed and
- lowercased before validation. Omit for a random, non-guessable mx\\__-prefixed
- address.
+ local_part: Optional mailbox name before the "@". Omit to generate a random address.
extra_headers: Send extra headers
@@ -493,6 +492,7 @@ async def create(
{
"client_request_id": client_request_id,
"billing_preference": billing_preference,
+ "domain_id": domain_id,
"label": label,
"local_part": local_part,
},
@@ -625,12 +625,9 @@ async def delete(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> MailboxDeleteResponse:
- """For paid rent, schedules end-of-cycle cancellation.
-
- For an included generation,
- archives immediately and releases its package seat. This never deletes the
- mailbox, its address, or its messages — the address is permanently reserved.
- Idempotent.
+ """
+ Cancels a pending mailbox or schedules an active paid mailbox for cancellation.
+ Existing addresses and messages are retained. Repeating the request is safe.
Args:
extra_headers: Send extra headers
@@ -661,10 +658,7 @@ async def capacity(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> MailboxCapacityResponse:
- """
- Returns the authoritative number of package-funded mailbox claims currently
- available after local reservations.
- """
+ """Returns the number of mailboxes currently available through included capacity."""
return await self._get(
"/mailboxes/capacity",
options=make_request_options(
@@ -688,10 +682,10 @@ async def otp(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> MailboxOtpResponse:
- """
- Returns the highest-confidence, most recent OTP for the mailbox, restricted to
- messages of completed/active paid intervals. Does not wait server-side (SDKs
- poll). 200 with the best code, 204 when none matches.
+ """Returns the most likely recent OTP for the mailbox.
+
+ Returns 204 when no matching
+ code is available.
Args:
extra_headers: Send extra headers
@@ -728,7 +722,7 @@ async def restart(
self,
mailbox_id: str,
*,
- billing_preference: Literal["included", "rent"] | Omit = omit,
+ billing_preference: Literal["included", "included_only", "rent"] | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -736,13 +730,15 @@ async def restart(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> MailboxRestartResponse:
- """
- Starts a new generation on an archived mailbox, reusing the same permanent
- address. Uses included capacity first unless paid rent is requested.
+ """Restarts an archived mailbox with the same address.
+
+ Uses included capacity when
+ available unless paid service is requested.
Args:
- billing_preference: Funding preference. Omit or use included for included-first activation; rent
- always preserves package capacity and starts paid checkout.
+ billing_preference: included uses package capacity when available and otherwise starts paid
+ checkout; included_only fails without creating a paid reservation when no
+ included slot remains; rent always starts paid checkout.
extra_headers: Send extra headers
@@ -776,10 +772,10 @@ async def uncancel(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> MailboxUncancelResponse:
- """Retracts a scheduled end-of-cycle cancellation for the current generation.
+ """Withdraws a scheduled cancellation.
- Only
- valid while cancellation is pending.
+ Only available while cancellation is
+ pending.
Args:
extra_headers: Send extra headers
diff --git a/src/mobilerun_sdk/resources/mailboxes/messages.py b/src/mobilerun_sdk/resources/mailboxes/messages.py
index d1baa1f8..2e7c54cd 100644
--- a/src/mobilerun_sdk/resources/mailboxes/messages.py
+++ b/src/mobilerun_sdk/resources/mailboxes/messages.py
@@ -101,8 +101,8 @@ def list(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> MessageListResponse:
"""
- Lists messages for a mailbox with keyset pagination and time/sender/hasOtp
- filters for polling.
+ Lists mailbox messages with cursor pagination and optional time, sender, and OTP
+ filters.
Args:
extra_headers: Send extra headers
@@ -212,8 +212,8 @@ async def list(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> MessageListResponse:
"""
- Lists messages for a mailbox with keyset pagination and time/sender/hasOtp
- filters for polling.
+ Lists mailbox messages with cursor pagination and optional time, sender, and OTP
+ filters.
Args:
extra_headers: Send extra headers
diff --git a/src/mobilerun_sdk/resources/messages/conversations.py b/src/mobilerun_sdk/resources/messages/conversations.py
index 9ef14bfa..397a5a3e 100644
--- a/src/mobilerun_sdk/resources/messages/conversations.py
+++ b/src/mobilerun_sdk/resources/messages/conversations.py
@@ -60,19 +60,10 @@ def list(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> ConversationListResponse:
- """Lists the caller's own SMS conversations, one row per thread.
+ """Lists SMS conversations by recent activity.
- Each row includes
- the most recent message in the thread, its unread inbound count, and the eSIMs
- it was seen through. Optional `esimId` or `numberId` narrows to threads on one
- eSIM or number.
-
- Cursor-paginated via `limit` (default 20, max 100) and
- `cursorLastOccurredAt`/`cursorLastMessageId` (both required together, taken from
- a previous page's `nextCursor`). Pagination follows each thread's most recent
- activity rather than a fixed snapshot, so a thread with new activity can move
- ahead of an in-progress page fetch. Clients that need a stable ordering should
- snapshot their own view.
+ Use both cursor fields from
+ `nextCursor` to fetch the next page.
Args:
extra_headers: Send extra headers
@@ -118,10 +109,8 @@ def mark_read(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> ConversationMarkReadResponse:
"""
- Marks the caller's own inbound messages in a conversation thread as read, up to
- and including the given `(upToOccurredAt, upToMessageId)` cursor — typically a
- conversation row's `lastMessage`. Idempotent: repeating the call with the same
- cursor updates 0 rows. Returns the number of rows updated.
+ Marks inbound messages in a conversation as read through the supplied cursor.
+ Repeating the request is safe.
Args:
peer_key: The thread's canonical peer key (see GET .../conversations)
@@ -189,19 +178,10 @@ async def list(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> ConversationListResponse:
- """Lists the caller's own SMS conversations, one row per thread.
-
- Each row includes
- the most recent message in the thread, its unread inbound count, and the eSIMs
- it was seen through. Optional `esimId` or `numberId` narrows to threads on one
- eSIM or number.
+ """Lists SMS conversations by recent activity.
- Cursor-paginated via `limit` (default 20, max 100) and
- `cursorLastOccurredAt`/`cursorLastMessageId` (both required together, taken from
- a previous page's `nextCursor`). Pagination follows each thread's most recent
- activity rather than a fixed snapshot, so a thread with new activity can move
- ahead of an in-progress page fetch. Clients that need a stable ordering should
- snapshot their own view.
+ Use both cursor fields from
+ `nextCursor` to fetch the next page.
Args:
extra_headers: Send extra headers
@@ -247,10 +227,8 @@ async def mark_read(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> ConversationMarkReadResponse:
"""
- Marks the caller's own inbound messages in a conversation thread as read, up to
- and including the given `(upToOccurredAt, upToMessageId)` cursor — typically a
- conversation row's `lastMessage`. Idempotent: repeating the call with the same
- cursor updates 0 rows. Returns the number of rows updated.
+ Marks inbound messages in a conversation as read through the supplied cursor.
+ Repeating the request is safe.
Args:
peer_key: The thread's canonical peer key (see GET .../conversations)
diff --git a/src/mobilerun_sdk/resources/messages/messages.py b/src/mobilerun_sdk/resources/messages/messages.py
index 2e5f30b6..49cc99a2 100644
--- a/src/mobilerun_sdk/resources/messages/messages.py
+++ b/src/mobilerun_sdk/resources/messages/messages.py
@@ -76,12 +76,9 @@ def list(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> MessageListResponse:
- """Lists the caller's own SMS messages, newest first.
-
- Supports filtering by
- direction, esimId, numberId, status, peerNumber (substring search, min 3
- characters), and peerKey (exact thread match). Each row includes its canonical
- thread key (`peerKey`).
+ """
+ Lists SMS messages newest first, with filters for direction, eSIM, phone number,
+ status, and conversation.
Args:
extra_headers: Send extra headers
@@ -162,12 +159,9 @@ async def list(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> MessageListResponse:
- """Lists the caller's own SMS messages, newest first.
-
- Supports filtering by
- direction, esimId, numberId, status, peerNumber (substring search, min 3
- characters), and peerKey (exact thread match). Each row includes its canonical
- thread key (`peerKey`).
+ """
+ Lists SMS messages newest first, with filters for direction, eSIM, phone number,
+ status, and conversation.
Args:
extra_headers: Send extra headers
diff --git a/src/mobilerun_sdk/resources/numbers/numbers.py b/src/mobilerun_sdk/resources/numbers/numbers.py
index 7b39353f..25bd6717 100644
--- a/src/mobilerun_sdk/resources/numbers/numbers.py
+++ b/src/mobilerun_sdk/resources/numbers/numbers.py
@@ -65,7 +65,7 @@ def with_streaming_response(self) -> NumbersResourceWithStreamingResponse:
def create(
self,
*,
- billing_preference: Literal["included", "rent"] | Omit = omit,
+ billing_preference: Literal["included", "included_only", "rent"] | Omit = omit,
country: str | Omit = omit,
label: Optional[str] | Omit = omit,
purpose: str | Omit = omit,
@@ -77,24 +77,23 @@ def create(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> NumberCreateResponse:
- """Starts a Mobilerun Phone purchase for the authenticated owner.
+ """Starts a phone-number purchase.
- Accepted requests
- always return the same asynchronous envelope; poll GET /numbers/phones/{id} for
- its business state. `purpose` and `country` are mutually exclusive.
+ Poll the returned phone number for status
+ updates. `purpose` and `country` cannot be combined.
Args:
- billing_preference: Prefer a free package seat ('included', default) or force the paid checkout
- ('rent')
+ billing_preference: Use included capacity when available, require included capacity without paid
+ fallback (included_only), or start a paid checkout (rent).
- country: Optional ISO 3166-1 alpha-2 country code from GET /numbers/countries. Cannot be
- combined with `purpose`.
+ country: Optional ISO 3166-1 alpha-2 country code from GET /numbers/phones/countries.
+ Cannot be combined with `purpose`.
label: User-defined display label — NFC-normalized, up to 100 GRAPHEMES (not UTF-16
code units; an emoji/flag may span several). Display-only, never used for
routing. Also seeds the billing entity name at purchase.
- purpose: Optional Mobilerun Phone purpose slug from GET /numbers/purposes.
+ purpose: Optional purpose from GET /numbers/phones/purposes.
idempotency_key: Optional request idempotency key.
@@ -169,13 +168,10 @@ def update(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> NumberUpdateResponse:
- """Updates the phone number's user-defined display label.
+ """Updates the display label.
- Omitting `label` leaves
- it unchanged; setting it to null or an empty string clears it. The label is
- capped at 100 characters, is display-only, and never affects routing. It also
- seeds the billing entity name when set at purchase time; a later change here
- does not rename the already-created billing entity.
+ Omitting `label` leaves it unchanged; null or an
+ empty string clears it.
Args:
label: User-defined display label — NFC-normalized, up to 100 GRAPHEMES (not UTF-16
@@ -214,8 +210,7 @@ def list(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> NumberListResponse:
"""
- Lists phone numbers owned by the authenticated user — both BYO (`user`) and
- provisioned (`mobilerun`) numbers.
+ Lists the caller's phone numbers.
Args:
extra_headers: Send extra headers
@@ -255,25 +250,10 @@ def delete(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> NumberDeleteResponse:
- """Cancels a Mobilerun Phone.
-
- The outcome depends on the number's current state:
-
- - If the number is still awaiting payment and no payment for it is currently
- being processed, the checkout is closed immediately and the number is retired.
- - If the number is on the standard paid plan and already paid and in service,
- cancellation is scheduled for the end of the current billing period rather
- than taking effect immediately. The number stays usable through the period
- already paid for, with no partial refund. Calling this again while a
- cancellation is already scheduled is a no-op that returns the same result. The
- response's `state` reflects this as `cancel_scheduled` with
- `cancelAtPeriodEnd: true`; `currentPeriodEnd` is populated once billing
- confirms the cancellation.
-
- Any other state (already refunding, a permanent billing failure, a payment
- currently being processed, an included-plan number, or a non-hosted/BYO number)
- returns 409 `not_cancellable`. Returns 404 if the number doesn't exist or isn't
- owned by the caller.
+ """
+ Cancels a pending purchase or schedules cancellation of an active paid phone
+ number. Repeating a scheduled cancellation is safe. Returns 409 when
+ cancellation is not available.
Args:
extra_headers: Send extra headers
@@ -304,10 +284,7 @@ def countries(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> NumberCountriesResponse:
- """
- Lists the countries currently offered for a dedicated Mobilerun Phone, with live
- stock status. Pass `country` as the `country` field on POST /numbers/phones.
- """
+ """Lists available countries and current phone-number availability."""
return self._get(
"/numbers/phones/countries",
options=make_request_options(
@@ -363,7 +340,7 @@ def with_streaming_response(self) -> AsyncNumbersResourceWithStreamingResponse:
async def create(
self,
*,
- billing_preference: Literal["included", "rent"] | Omit = omit,
+ billing_preference: Literal["included", "included_only", "rent"] | Omit = omit,
country: str | Omit = omit,
label: Optional[str] | Omit = omit,
purpose: str | Omit = omit,
@@ -375,24 +352,23 @@ async def create(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> NumberCreateResponse:
- """Starts a Mobilerun Phone purchase for the authenticated owner.
+ """Starts a phone-number purchase.
- Accepted requests
- always return the same asynchronous envelope; poll GET /numbers/phones/{id} for
- its business state. `purpose` and `country` are mutually exclusive.
+ Poll the returned phone number for status
+ updates. `purpose` and `country` cannot be combined.
Args:
- billing_preference: Prefer a free package seat ('included', default) or force the paid checkout
- ('rent')
+ billing_preference: Use included capacity when available, require included capacity without paid
+ fallback (included_only), or start a paid checkout (rent).
- country: Optional ISO 3166-1 alpha-2 country code from GET /numbers/countries. Cannot be
- combined with `purpose`.
+ country: Optional ISO 3166-1 alpha-2 country code from GET /numbers/phones/countries.
+ Cannot be combined with `purpose`.
label: User-defined display label — NFC-normalized, up to 100 GRAPHEMES (not UTF-16
code units; an emoji/flag may span several). Display-only, never used for
routing. Also seeds the billing entity name at purchase.
- purpose: Optional Mobilerun Phone purpose slug from GET /numbers/purposes.
+ purpose: Optional purpose from GET /numbers/phones/purposes.
idempotency_key: Optional request idempotency key.
@@ -467,13 +443,10 @@ async def update(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> NumberUpdateResponse:
- """Updates the phone number's user-defined display label.
+ """Updates the display label.
- Omitting `label` leaves
- it unchanged; setting it to null or an empty string clears it. The label is
- capped at 100 characters, is display-only, and never affects routing. It also
- seeds the billing entity name when set at purchase time; a later change here
- does not rename the already-created billing entity.
+ Omitting `label` leaves it unchanged; null or an
+ empty string clears it.
Args:
label: User-defined display label — NFC-normalized, up to 100 GRAPHEMES (not UTF-16
@@ -512,8 +485,7 @@ async def list(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> NumberListResponse:
"""
- Lists phone numbers owned by the authenticated user — both BYO (`user`) and
- provisioned (`mobilerun`) numbers.
+ Lists the caller's phone numbers.
Args:
extra_headers: Send extra headers
@@ -553,25 +525,10 @@ async def delete(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> NumberDeleteResponse:
- """Cancels a Mobilerun Phone.
-
- The outcome depends on the number's current state:
-
- - If the number is still awaiting payment and no payment for it is currently
- being processed, the checkout is closed immediately and the number is retired.
- - If the number is on the standard paid plan and already paid and in service,
- cancellation is scheduled for the end of the current billing period rather
- than taking effect immediately. The number stays usable through the period
- already paid for, with no partial refund. Calling this again while a
- cancellation is already scheduled is a no-op that returns the same result. The
- response's `state` reflects this as `cancel_scheduled` with
- `cancelAtPeriodEnd: true`; `currentPeriodEnd` is populated once billing
- confirms the cancellation.
-
- Any other state (already refunding, a permanent billing failure, a payment
- currently being processed, an included-plan number, or a non-hosted/BYO number)
- returns 409 `not_cancellable`. Returns 404 if the number doesn't exist or isn't
- owned by the caller.
+ """
+ Cancels a pending purchase or schedules cancellation of an active paid phone
+ number. Repeating a scheduled cancellation is safe. Returns 409 when
+ cancellation is not available.
Args:
extra_headers: Send extra headers
@@ -602,10 +559,7 @@ async def countries(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> NumberCountriesResponse:
- """
- Lists the countries currently offered for a dedicated Mobilerun Phone, with live
- stock status. Pass `country` as the `country` field on POST /numbers/phones.
- """
+ """Lists available countries and current phone-number availability."""
return await self._get(
"/numbers/phones/countries",
options=make_request_options(
diff --git a/src/mobilerun_sdk/resources/tasks/tasks.py b/src/mobilerun_sdk/resources/tasks/tasks.py
index e73ca6bb..c6656997 100644
--- a/src/mobilerun_sdk/resources/tasks/tasks.py
+++ b/src/mobilerun_sdk/resources/tasks/tasks.py
@@ -121,7 +121,10 @@ def list(
page: int | Omit = omit,
page_size: int | Omit = omit,
query: Optional[str] | Omit = omit,
- status: Optional[Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"]]
+ source: Optional[Literal["api", "agent"]] | Omit = omit,
+ status: Optional[
+ Literal["prepared", "queued", "created", "running", "cancelling", "completed", "failed", "cancelled"]
+ ]
| Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -140,6 +143,8 @@ def list(
query: Search in task description.
+ source: Only tasks created via the API ('api') or spawned by an agent step ('agent').
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -164,6 +169,7 @@ def list(
"page": page,
"page_size": page_size,
"query": query,
+ "source": source,
"status": status,
},
task_list_params.TaskListParams,
@@ -278,7 +284,6 @@ def run(
device_id: str,
task: str,
accessibility: bool | Omit = omit,
- agent_id: int | Omit = omit,
apps: SequenceNotStr[str] | Omit = omit,
continue_on_failure: bool | Omit = omit,
credentials: Iterable[task_run_params.Credential] | Omit = omit,
@@ -287,11 +292,12 @@ def run(
files: SequenceNotStr[str] | Omit = omit,
llm_model: str | Omit = omit,
max_steps: int | Omit = omit,
- memory_namespace: str | Omit = omit,
output_schema: Optional[Dict[str, object]] | Omit = omit,
reasoning: bool | Omit = omit,
+ recording_enabled: bool | Omit = omit,
stealth: bool | Omit = omit,
subagent_model: str | Omit = omit,
+ system_prompt: Optional[str] | Omit = omit,
temperature: float | Omit = omit,
vision: bool | Omit = omit,
vpn_country: Optional[Literal["US", "BR", "FR", "DE", "IN", "JP", "KR", "ZA"]] | Omit = omit,
@@ -313,12 +319,19 @@ def run(
display_id: The display ID of the device to run the task on.
- llm_model: The LLM model identifier to use for the task (e.g. 'google/gemini-3.5-flash')
+ execution_timeout: Maximum agent execution time in seconds (1–2700).
+
+ llm_model: The LLM model identifier to use for the task (e.g. 'openai/gpt-5.6-luna')
- memory_namespace: Memory namespace for cross-task personalization
+ recording_enabled: Record device video for the whole task and persist a retrievable reference
subagent_model: LLM model used by sub-agent roles: executor, app_opener, structured_output
+ system_prompt: Optional custom behavioral overlay applied on top of the agent's default system
+ prompts. Never echoed back in responses or errors.
+
+ temperature: Deprecated and ignored. Sampling behavior is controlled by the model provider.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -335,7 +348,6 @@ def run(
"device_id": device_id,
"task": task,
"accessibility": accessibility,
- "agent_id": agent_id,
"apps": apps,
"continue_on_failure": continue_on_failure,
"credentials": credentials,
@@ -344,11 +356,12 @@ def run(
"files": files,
"llm_model": llm_model,
"max_steps": max_steps,
- "memory_namespace": memory_namespace,
"output_schema": output_schema,
"reasoning": reasoning,
+ "recording_enabled": recording_enabled,
"stealth": stealth,
"subagent_model": subagent_model,
+ "system_prompt": system_prompt,
"temperature": temperature,
"vision": vision,
"vpn_country": vpn_country,
@@ -367,7 +380,6 @@ def run_streamed(
device_id: str,
task: str,
accessibility: bool | Omit = omit,
- agent_id: int | Omit = omit,
apps: SequenceNotStr[str] | Omit = omit,
continue_on_failure: bool | Omit = omit,
credentials: Iterable[task_run_streamed_params.Credential] | Omit = omit,
@@ -376,11 +388,12 @@ def run_streamed(
files: SequenceNotStr[str] | Omit = omit,
llm_model: str | Omit = omit,
max_steps: int | Omit = omit,
- memory_namespace: str | Omit = omit,
output_schema: Optional[Dict[str, object]] | Omit = omit,
reasoning: bool | Omit = omit,
+ recording_enabled: bool | Omit = omit,
stealth: bool | Omit = omit,
subagent_model: str | Omit = omit,
+ system_prompt: Optional[str] | Omit = omit,
temperature: float | Omit = omit,
vision: bool | Omit = omit,
vpn_country: Optional[Literal["US", "BR", "FR", "DE", "IN", "JP", "KR", "ZA"]] | Omit = omit,
@@ -400,12 +413,19 @@ def run_streamed(
display_id: The display ID of the device to run the task on.
- llm_model: The LLM model identifier to use for the task (e.g. 'google/gemini-3.5-flash')
+ execution_timeout: Maximum agent execution time in seconds (1–2700).
- memory_namespace: Memory namespace for cross-task personalization
+ llm_model: The LLM model identifier to use for the task (e.g. 'openai/gpt-5.6-luna')
+
+ recording_enabled: Record device video for the whole task and persist a retrievable reference
subagent_model: LLM model used by sub-agent roles: executor, app_opener, structured_output
+ system_prompt: Optional custom behavioral overlay applied on top of the agent's default system
+ prompts. Never echoed back in responses or errors.
+
+ temperature: Deprecated and ignored. Sampling behavior is controlled by the model provider.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -421,7 +441,6 @@ def run_streamed(
"device_id": device_id,
"task": task,
"accessibility": accessibility,
- "agent_id": agent_id,
"apps": apps,
"continue_on_failure": continue_on_failure,
"credentials": credentials,
@@ -430,11 +449,12 @@ def run_streamed(
"files": files,
"llm_model": llm_model,
"max_steps": max_steps,
- "memory_namespace": memory_namespace,
"output_schema": output_schema,
"reasoning": reasoning,
+ "recording_enabled": recording_enabled,
"stealth": stealth,
"subagent_model": subagent_model,
+ "system_prompt": system_prompt,
"temperature": temperature,
"vision": vision,
"vpn_country": vpn_country,
@@ -597,7 +617,10 @@ async def list(
page: int | Omit = omit,
page_size: int | Omit = omit,
query: Optional[str] | Omit = omit,
- status: Optional[Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"]]
+ source: Optional[Literal["api", "agent"]] | Omit = omit,
+ status: Optional[
+ Literal["prepared", "queued", "created", "running", "cancelling", "completed", "failed", "cancelled"]
+ ]
| Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -616,6 +639,8 @@ async def list(
query: Search in task description.
+ source: Only tasks created via the API ('api') or spawned by an agent step ('agent').
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -640,6 +665,7 @@ async def list(
"page": page,
"page_size": page_size,
"query": query,
+ "source": source,
"status": status,
},
task_list_params.TaskListParams,
@@ -754,7 +780,6 @@ async def run(
device_id: str,
task: str,
accessibility: bool | Omit = omit,
- agent_id: int | Omit = omit,
apps: SequenceNotStr[str] | Omit = omit,
continue_on_failure: bool | Omit = omit,
credentials: Iterable[task_run_params.Credential] | Omit = omit,
@@ -763,11 +788,12 @@ async def run(
files: SequenceNotStr[str] | Omit = omit,
llm_model: str | Omit = omit,
max_steps: int | Omit = omit,
- memory_namespace: str | Omit = omit,
output_schema: Optional[Dict[str, object]] | Omit = omit,
reasoning: bool | Omit = omit,
+ recording_enabled: bool | Omit = omit,
stealth: bool | Omit = omit,
subagent_model: str | Omit = omit,
+ system_prompt: Optional[str] | Omit = omit,
temperature: float | Omit = omit,
vision: bool | Omit = omit,
vpn_country: Optional[Literal["US", "BR", "FR", "DE", "IN", "JP", "KR", "ZA"]] | Omit = omit,
@@ -789,12 +815,19 @@ async def run(
display_id: The display ID of the device to run the task on.
- llm_model: The LLM model identifier to use for the task (e.g. 'google/gemini-3.5-flash')
+ execution_timeout: Maximum agent execution time in seconds (1–2700).
+
+ llm_model: The LLM model identifier to use for the task (e.g. 'openai/gpt-5.6-luna')
- memory_namespace: Memory namespace for cross-task personalization
+ recording_enabled: Record device video for the whole task and persist a retrievable reference
subagent_model: LLM model used by sub-agent roles: executor, app_opener, structured_output
+ system_prompt: Optional custom behavioral overlay applied on top of the agent's default system
+ prompts. Never echoed back in responses or errors.
+
+ temperature: Deprecated and ignored. Sampling behavior is controlled by the model provider.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -811,7 +844,6 @@ async def run(
"device_id": device_id,
"task": task,
"accessibility": accessibility,
- "agent_id": agent_id,
"apps": apps,
"continue_on_failure": continue_on_failure,
"credentials": credentials,
@@ -820,11 +852,12 @@ async def run(
"files": files,
"llm_model": llm_model,
"max_steps": max_steps,
- "memory_namespace": memory_namespace,
"output_schema": output_schema,
"reasoning": reasoning,
+ "recording_enabled": recording_enabled,
"stealth": stealth,
"subagent_model": subagent_model,
+ "system_prompt": system_prompt,
"temperature": temperature,
"vision": vision,
"vpn_country": vpn_country,
@@ -843,7 +876,6 @@ async def run_streamed(
device_id: str,
task: str,
accessibility: bool | Omit = omit,
- agent_id: int | Omit = omit,
apps: SequenceNotStr[str] | Omit = omit,
continue_on_failure: bool | Omit = omit,
credentials: Iterable[task_run_streamed_params.Credential] | Omit = omit,
@@ -852,11 +884,12 @@ async def run_streamed(
files: SequenceNotStr[str] | Omit = omit,
llm_model: str | Omit = omit,
max_steps: int | Omit = omit,
- memory_namespace: str | Omit = omit,
output_schema: Optional[Dict[str, object]] | Omit = omit,
reasoning: bool | Omit = omit,
+ recording_enabled: bool | Omit = omit,
stealth: bool | Omit = omit,
subagent_model: str | Omit = omit,
+ system_prompt: Optional[str] | Omit = omit,
temperature: float | Omit = omit,
vision: bool | Omit = omit,
vpn_country: Optional[Literal["US", "BR", "FR", "DE", "IN", "JP", "KR", "ZA"]] | Omit = omit,
@@ -876,12 +909,19 @@ async def run_streamed(
display_id: The display ID of the device to run the task on.
- llm_model: The LLM model identifier to use for the task (e.g. 'google/gemini-3.5-flash')
+ execution_timeout: Maximum agent execution time in seconds (1–2700).
- memory_namespace: Memory namespace for cross-task personalization
+ llm_model: The LLM model identifier to use for the task (e.g. 'openai/gpt-5.6-luna')
+
+ recording_enabled: Record device video for the whole task and persist a retrievable reference
subagent_model: LLM model used by sub-agent roles: executor, app_opener, structured_output
+ system_prompt: Optional custom behavioral overlay applied on top of the agent's default system
+ prompts. Never echoed back in responses or errors.
+
+ temperature: Deprecated and ignored. Sampling behavior is controlled by the model provider.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -897,7 +937,6 @@ async def run_streamed(
"device_id": device_id,
"task": task,
"accessibility": accessibility,
- "agent_id": agent_id,
"apps": apps,
"continue_on_failure": continue_on_failure,
"credentials": credentials,
@@ -906,11 +945,12 @@ async def run_streamed(
"files": files,
"llm_model": llm_model,
"max_steps": max_steps,
- "memory_namespace": memory_namespace,
"output_schema": output_schema,
"reasoning": reasoning,
+ "recording_enabled": recording_enabled,
"stealth": stealth,
"subagent_model": subagent_model,
+ "system_prompt": system_prompt,
"temperature": temperature,
"vision": vision,
"vpn_country": vpn_country,
diff --git a/src/mobilerun_sdk/resources/workflows/executions.py b/src/mobilerun_sdk/resources/workflows/executions.py
index cb7e5a19..cc3f03bd 100644
--- a/src/mobilerun_sdk/resources/workflows/executions.py
+++ b/src/mobilerun_sdk/resources/workflows/executions.py
@@ -86,6 +86,7 @@ def list(
*,
flow_id: str | Omit = omit,
from_: Optional[str] | Omit = omit,
+ invocation_id: str | Omit = omit,
order_by: Literal["startedAt", "finishedAt", "status"] | Omit = omit,
order_by_direction: Literal["asc", "desc"] | Omit = omit,
page: int | Omit = omit,
@@ -104,8 +105,9 @@ def list(
"""Return a paginated history of flow executions.
Supports filtering by `flowId`,
- `triggerId`, `status`, and a `from`/`to` time range, plus free-text `search` and
- ordering by startedAt, finishedAt, or status.
+ `triggerId`, `invocationId` (the client/verify key), `status`, and a `from`/`to`
+ time range, plus free-text `search` and ordering by startedAt, finishedAt, or
+ status.
Args:
extra_headers: Send extra headers
@@ -127,6 +129,7 @@ def list(
{
"flow_id": flow_id,
"from_": from_,
+ "invocation_id": invocation_id,
"order_by": order_by,
"order_by_direction": order_by_direction,
"page": page,
@@ -284,6 +287,7 @@ async def list(
*,
flow_id: str | Omit = omit,
from_: Optional[str] | Omit = omit,
+ invocation_id: str | Omit = omit,
order_by: Literal["startedAt", "finishedAt", "status"] | Omit = omit,
order_by_direction: Literal["asc", "desc"] | Omit = omit,
page: int | Omit = omit,
@@ -302,8 +306,9 @@ async def list(
"""Return a paginated history of flow executions.
Supports filtering by `flowId`,
- `triggerId`, `status`, and a `from`/`to` time range, plus free-text `search` and
- ordering by startedAt, finishedAt, or status.
+ `triggerId`, `invocationId` (the client/verify key), `status`, and a `from`/`to`
+ time range, plus free-text `search` and ordering by startedAt, finishedAt, or
+ status.
Args:
extra_headers: Send extra headers
@@ -325,6 +330,7 @@ async def list(
{
"flow_id": flow_id,
"from_": from_,
+ "invocation_id": invocation_id,
"order_by": order_by,
"order_by_direction": order_by_direction,
"page": page,
diff --git a/src/mobilerun_sdk/resources/workflows/flows/actions.py b/src/mobilerun_sdk/resources/workflows/flows/actions.py
index 0fd2150d..26ca8773 100644
--- a/src/mobilerun_sdk/resources/workflows/flows/actions.py
+++ b/src/mobilerun_sdk/resources/workflows/flows/actions.py
@@ -91,6 +91,7 @@ def add(
name_override: str | Omit = omit,
overrides: Optional[action_add_params.Overrides] | Omit = omit,
parent_flow_action_id: Optional[str] | Omit = omit,
+ recording_enabled: bool | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -126,6 +127,7 @@ def add(
"name_override": name_override,
"overrides": overrides,
"parent_flow_action_id": parent_flow_action_id,
+ "recording_enabled": recording_enabled,
},
action_add_params.ActionAddParams,
),
@@ -277,6 +279,7 @@ async def add(
name_override: str | Omit = omit,
overrides: Optional[action_add_params.Overrides] | Omit = omit,
parent_flow_action_id: Optional[str] | Omit = omit,
+ recording_enabled: bool | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -312,6 +315,7 @@ async def add(
"name_override": name_override,
"overrides": overrides,
"parent_flow_action_id": parent_flow_action_id,
+ "recording_enabled": recording_enabled,
},
action_add_params.ActionAddParams,
),
diff --git a/src/mobilerun_sdk/resources/workflows/flows/flows.py b/src/mobilerun_sdk/resources/workflows/flows/flows.py
index db390fcc..adb266d1 100644
--- a/src/mobilerun_sdk/resources/workflows/flows/flows.py
+++ b/src/mobilerun_sdk/resources/workflows/flows/flows.py
@@ -86,6 +86,7 @@ def create(
notify_on_success: bool | Omit = omit,
notify_webhook_id: Optional[str] | Omit = omit,
recording_enabled: bool | Omit = omit,
+ recording_policy: flow_create_params.RecordingPolicy | Omit = omit,
self_healing_enabled: bool | Omit = omit,
self_healing_max_attempts: int | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -102,6 +103,9 @@ def create(
success or failure.
Args:
+ recording_enabled: Deprecated compatibility field. true maps to recordingPolicy.mode="flow"; false
+ maps to "off".
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -127,6 +131,7 @@ def create(
"notify_on_success": notify_on_success,
"notify_webhook_id": notify_webhook_id,
"recording_enabled": recording_enabled,
+ "recording_policy": recording_policy,
"self_healing_enabled": self_healing_enabled,
"self_healing_max_attempts": self_healing_max_attempts,
},
@@ -182,11 +187,13 @@ def update(
device_ids: SequenceNotStr[str] | Omit = omit,
enabled: bool | Omit = omit,
health_monitoring_enabled: bool | Omit = omit,
+ lifecycle_status: Literal["enabled", "disabled"] | Omit = omit,
name: str | Omit = omit,
notify_on_failure: bool | Omit = omit,
notify_on_success: bool | Omit = omit,
notify_webhook_id: Optional[str] | Omit = omit,
recording_enabled: bool | Omit = omit,
+ recording_policy: flow_update_params.RecordingPolicy | Omit = omit,
self_healing_enabled: bool | Omit = omit,
self_healing_max_attempts: int | Omit = omit,
trigger_id: str | Omit = omit,
@@ -204,6 +211,11 @@ def update(
does not exist.
Args:
+ lifecycle_status: Set the visible agent lifecycle. Archive remains available only through DELETE.
+
+ recording_enabled: Deprecated compatibility field. true maps to recordingPolicy.mode="flow"; false
+ maps to "off".
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -224,11 +236,13 @@ def update(
"device_ids": device_ids,
"enabled": enabled,
"health_monitoring_enabled": health_monitoring_enabled,
+ "lifecycle_status": lifecycle_status,
"name": name,
"notify_on_failure": notify_on_failure,
"notify_on_success": notify_on_success,
"notify_webhook_id": notify_webhook_id,
"recording_enabled": recording_enabled,
+ "recording_policy": recording_policy,
"self_healing_enabled": self_healing_enabled,
"self_healing_max_attempts": self_healing_max_attempts,
"trigger_id": trigger_id,
@@ -318,9 +332,10 @@ def delete(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> FlowDeleteResponse:
- """Delete a flow by its ID.
+ """Terminally archive a flow by its ID.
- Returns 404 if no flow matches.
+ Archived flows cannot be restored and are
+ hidden from customer reads. Repeating the request is idempotent for the owner.
Args:
extra_headers: Send extra headers
@@ -543,6 +558,7 @@ async def create(
notify_on_success: bool | Omit = omit,
notify_webhook_id: Optional[str] | Omit = omit,
recording_enabled: bool | Omit = omit,
+ recording_policy: flow_create_params.RecordingPolicy | Omit = omit,
self_healing_enabled: bool | Omit = omit,
self_healing_max_attempts: int | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
@@ -559,6 +575,9 @@ async def create(
success or failure.
Args:
+ recording_enabled: Deprecated compatibility field. true maps to recordingPolicy.mode="flow"; false
+ maps to "off".
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -584,6 +603,7 @@ async def create(
"notify_on_success": notify_on_success,
"notify_webhook_id": notify_webhook_id,
"recording_enabled": recording_enabled,
+ "recording_policy": recording_policy,
"self_healing_enabled": self_healing_enabled,
"self_healing_max_attempts": self_healing_max_attempts,
},
@@ -639,11 +659,13 @@ async def update(
device_ids: SequenceNotStr[str] | Omit = omit,
enabled: bool | Omit = omit,
health_monitoring_enabled: bool | Omit = omit,
+ lifecycle_status: Literal["enabled", "disabled"] | Omit = omit,
name: str | Omit = omit,
notify_on_failure: bool | Omit = omit,
notify_on_success: bool | Omit = omit,
notify_webhook_id: Optional[str] | Omit = omit,
recording_enabled: bool | Omit = omit,
+ recording_policy: flow_update_params.RecordingPolicy | Omit = omit,
self_healing_enabled: bool | Omit = omit,
self_healing_max_attempts: int | Omit = omit,
trigger_id: str | Omit = omit,
@@ -661,6 +683,11 @@ async def update(
does not exist.
Args:
+ lifecycle_status: Set the visible agent lifecycle. Archive remains available only through DELETE.
+
+ recording_enabled: Deprecated compatibility field. true maps to recordingPolicy.mode="flow"; false
+ maps to "off".
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -681,11 +708,13 @@ async def update(
"device_ids": device_ids,
"enabled": enabled,
"health_monitoring_enabled": health_monitoring_enabled,
+ "lifecycle_status": lifecycle_status,
"name": name,
"notify_on_failure": notify_on_failure,
"notify_on_success": notify_on_success,
"notify_webhook_id": notify_webhook_id,
"recording_enabled": recording_enabled,
+ "recording_policy": recording_policy,
"self_healing_enabled": self_healing_enabled,
"self_healing_max_attempts": self_healing_max_attempts,
"trigger_id": trigger_id,
@@ -775,9 +804,10 @@ async def delete(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> FlowDeleteResponse:
- """Delete a flow by its ID.
+ """Terminally archive a flow by its ID.
- Returns 404 if no flow matches.
+ Archived flows cannot be restored and are
+ hidden from customer reads. Repeating the request is idempotent for the owner.
Args:
extra_headers: Send extra headers
diff --git a/src/mobilerun_sdk/resources/workflows/triggers.py b/src/mobilerun_sdk/resources/workflows/triggers.py
index d569d1eb..752cd1dd 100644
--- a/src/mobilerun_sdk/resources/workflows/triggers.py
+++ b/src/mobilerun_sdk/resources/workflows/triggers.py
@@ -291,6 +291,7 @@ def fire(
trigger_id: str,
*,
payload: Dict[str, object],
+ invocation_id: str | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -322,6 +323,10 @@ def fire(
Validated against the trigger's customPayloadSchema when one is configured;
otherwise only "must be a JSON object" is enforced.
+ invocation_id: Optional client-supplied idempotency key. When provided, a flow that already has
+ an execution for this (flow, invocationId) is skipped and `deduplicated` is
+ true. When omitted a fresh server-side id is generated (no dedup).
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -334,7 +339,13 @@ def fire(
raise ValueError(f"Expected a non-empty value for `trigger_id` but received {trigger_id!r}")
return self._post(
path_template("/triggers/{trigger_id}/fire", trigger_id=trigger_id),
- body=maybe_transform({"payload": payload}, trigger_fire_params.TriggerFireParams),
+ body=maybe_transform(
+ {
+ "payload": payload,
+ "invocation_id": invocation_id,
+ },
+ trigger_fire_params.TriggerFireParams,
+ ),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -604,6 +615,7 @@ async def fire(
trigger_id: str,
*,
payload: Dict[str, object],
+ invocation_id: str | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -635,6 +647,10 @@ async def fire(
Validated against the trigger's customPayloadSchema when one is configured;
otherwise only "must be a JSON object" is enforced.
+ invocation_id: Optional client-supplied idempotency key. When provided, a flow that already has
+ an execution for this (flow, invocationId) is skipped and `deduplicated` is
+ true. When omitted a fresh server-side id is generated (no dedup).
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -647,7 +663,13 @@ async def fire(
raise ValueError(f"Expected a non-empty value for `trigger_id` but received {trigger_id!r}")
return await self._post(
path_template("/triggers/{trigger_id}/fire", trigger_id=trigger_id),
- body=await async_maybe_transform({"payload": payload}, trigger_fire_params.TriggerFireParams),
+ body=await async_maybe_transform(
+ {
+ "payload": payload,
+ "invocation_id": invocation_id,
+ },
+ trigger_fire_params.TriggerFireParams,
+ ),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
diff --git a/src/mobilerun_sdk/types/__init__.py b/src/mobilerun_sdk/types/__init__.py
index 310d2f0f..1748d456 100644
--- a/src/mobilerun_sdk/types/__init__.py
+++ b/src/mobilerun_sdk/types/__init__.py
@@ -17,17 +17,12 @@
)
from .app_list_params import AppListParams as AppListParams
from .task_run_params import TaskRunParams as TaskRunParams
-from .esim_list_params import EsimListParams as EsimListParams
from .file_list_params import FileListParams as FileListParams
from .task_list_params import TaskListParams as TaskListParams
from .app_list_response import AppListResponse as AppListResponse
from .proxy_list_params import ProxyListParams as ProxyListParams
from .task_run_response import TaskRunResponse as TaskRunResponse
from .device_list_params import DeviceListParams as DeviceListParams
-from .esim_create_params import EsimCreateParams as EsimCreateParams
-from .esim_import_params import EsimImportParams as EsimImportParams
-from .esim_list_response import EsimListResponse as EsimListResponse
-from .esim_update_params import EsimUpdateParams as EsimUpdateParams
from .file_list_response import FileListResponse as FileListResponse
from .file_update_params import FileUpdateParams as FileUpdateParams
from .mailbox_otp_params import MailboxOtpParams as MailboxOtpParams
@@ -36,7 +31,6 @@
from .task_stop_response import TaskStopResponse as TaskStopResponse
from .app_delete_response import AppDeleteResponse as AppDeleteResponse
from .carrier_list_params import CarrierListParams as CarrierListParams
-from .esim_install_params import EsimInstallParams as EsimInstallParams
from .mailbox_list_params import MailboxListParams as MailboxListParams
from .message_list_params import MessageListParams as MessageListParams
from .model_list_response import ModelListResponse as ModelListResponse
@@ -48,10 +42,6 @@
from .webhook_list_params import WebhookListParams as WebhookListParams
from .device_create_params import DeviceCreateParams as DeviceCreateParams
from .device_list_response import DeviceListResponse as DeviceListResponse
-from .esim_create_response import EsimCreateResponse as EsimCreateResponse
-from .esim_import_response import EsimImportResponse as EsimImportResponse
-from .esim_selector_params import EsimSelectorParams as EsimSelectorParams
-from .esim_update_response import EsimUpdateResponse as EsimUpdateResponse
from .file_delete_response import FileDeleteResponse as FileDeleteResponse
from .file_update_response import FileUpdateResponse as FileUpdateResponse
from .mailbox_otp_response import MailboxOtpResponse as MailboxOtpResponse
@@ -65,7 +55,6 @@
from .carrier_lookup_params import CarrierLookupParams as CarrierLookupParams
from .carrier_update_params import CarrierUpdateParams as CarrierUpdateParams
from .device_count_response import DeviceCountResponse as DeviceCountResponse
-from .esim_install_response import EsimInstallResponse as EsimInstallResponse
from .file_confirm_response import FileConfirmResponse as FileConfirmResponse
from .mailbox_create_params import MailboxCreateParams as MailboxCreateParams
from .mailbox_list_response import MailboxListResponse as MailboxListResponse
@@ -84,9 +73,6 @@
from .credential_list_params import CredentialListParams as CredentialListParams
from .device_create_response import DeviceCreateResponse as DeviceCreateResponse
from .device_set_name_params import DeviceSetNameParams as DeviceSetNameParams
-from .esim_capacity_response import EsimCapacityResponse as EsimCapacityResponse
-from .esim_retrieve_response import EsimRetrieveResponse as EsimRetrieveResponse
-from .esim_selector_response import EsimSelectorResponse as EsimSelectorResponse
from .file_upload_url_params import FileUploadURLParams as FileUploadURLParams
from .mailbox_restart_params import MailboxRestartParams as MailboxRestartParams
from .number_create_response import NumberCreateResponse as NumberCreateResponse
@@ -134,11 +120,9 @@
from .app_confirm_upload_response import AppConfirmUploadResponse as AppConfirmUploadResponse
from .app_event_retrieve_response import AppEventRetrieveResponse as AppEventRetrieveResponse
from .device_fingerprint_response import DeviceFingerprintResponse as DeviceFingerprintResponse
-from .esim_install_status_response import EsimInstallStatusResponse as EsimInstallStatusResponse
from .file_cancel_pending_response import FileCancelPendingResponse as FileCancelPendingResponse
from .task_get_trajectory_response import TaskGetTrajectoryResponse as TaskGetTrajectoryResponse
from .webhook_event_types_response import WebhookEventTypesResponse as WebhookEventTypesResponse
-from .esim_confirm_payment_response import EsimConfirmPaymentResponse as EsimConfirmPaymentResponse
from .notification_catalog_response import NotificationCatalogResponse as NotificationCatalogResponse
from .webhook_rotate_secret_response import WebhookRotateSecretResponse as WebhookRotateSecretResponse
from .webhook_test_delivery_response import WebhookTestDeliveryResponse as WebhookTestDeliveryResponse
diff --git a/src/mobilerun_sdk/types/app_storage_usage_response.py b/src/mobilerun_sdk/types/app_storage_usage_response.py
index f1c225ec..f9dd47c4 100644
--- a/src/mobilerun_sdk/types/app_storage_usage_response.py
+++ b/src/mobilerun_sdk/types/app_storage_usage_response.py
@@ -9,12 +9,19 @@
class Data(BaseModel):
available_bytes: float = FieldInfo(alias="availableBytes")
- """Remaining bytes — the reliable maximum size for the next upload.
+ """Remaining bytes — the reliable maximum TOTAL size for the next upload.
Advisory snapshot: the quota is enforced under a lock at confirm, so concurrent
uploads may reduce actual headroom.
"""
+ max_file_bytes: float = FieldInfo(alias="maxFileBytes")
+ """Per-file upload cap in bytes (env.MAX_UPLOAD_FILE_BYTES).
+
+ A single file larger than this is rejected at confirm even when it fits the
+ remaining quota. Source of truth for the client-side per-file limit.
+ """
+
quota_bytes: float = FieldInfo(alias="quotaBytes")
"""Total storage allowance for the user, in bytes"""
diff --git a/src/mobilerun_sdk/types/assistant/conversation_abort_params.py b/src/mobilerun_sdk/types/assistant/conversation_abort_params.py
index ced9a891..7c15bc34 100644
--- a/src/mobilerun_sdk/types/assistant/conversation_abort_params.py
+++ b/src/mobilerun_sdk/types/assistant/conversation_abort_params.py
@@ -11,3 +11,5 @@
class ConversationAbortParams(TypedDict, total=False):
session_id: Required[Annotated[str, PropertyInfo(alias="sessionId")]]
+
+ expected_turn_id: Annotated[str, PropertyInfo(alias="expectedTurnId")]
diff --git a/src/mobilerun_sdk/types/assistant/conversation_history_response.py b/src/mobilerun_sdk/types/assistant/conversation_history_response.py
index 8288033a..3adbc2e3 100644
--- a/src/mobilerun_sdk/types/assistant/conversation_history_response.py
+++ b/src/mobilerun_sdk/types/assistant/conversation_history_response.py
@@ -8,7 +8,7 @@
from ..._models import BaseModel
-__all__ = ["ConversationHistoryResponse", "Message", "MessagePart", "MessageMetadata"]
+__all__ = ["ConversationHistoryResponse", "Message", "MessagePart", "MessageMetadata", "TurnState"]
class MessagePart(BaseModel):
@@ -60,9 +60,33 @@ class Message(BaseModel):
"""Deprecated: use createdBy."""
+class TurnState(BaseModel):
+ id: str
+
+ abort_requested: bool = FieldInfo(alias="abortRequested")
+
+ attachable: bool
+
+ claim_held: bool = FieldInfo(alias="claimHeld")
+
+ outcome: Optional[str] = None
+
+ phase: Literal["created", "running", "closed", "delivered", "failed"]
+
+ reaping: bool
+
+ revision: int
+
+ started_at: str = FieldInfo(alias="startedAt")
+
+
class ConversationHistoryResponse(BaseModel):
messages: List[Message]
turn_active: bool = FieldInfo(alias="turnActive")
+ last_turn_outcome: Optional[str] = FieldInfo(alias="lastTurnOutcome", default=None)
+
truncated: Optional[bool] = None
+
+ turn_state: Optional[TurnState] = FieldInfo(alias="turnState", default=None)
diff --git a/src/mobilerun_sdk/types/connect/proxy_buy_params.py b/src/mobilerun_sdk/types/connect/proxy_buy_params.py
index b8147750..8426ebeb 100644
--- a/src/mobilerun_sdk/types/connect/proxy_buy_params.py
+++ b/src/mobilerun_sdk/types/connect/proxy_buy_params.py
@@ -2,7 +2,9 @@
from __future__ import annotations
-from typing_extensions import Literal, Required, TypedDict
+from typing_extensions import Literal, Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
__all__ = ["ProxyBuyParams"]
@@ -12,3 +14,5 @@ class ProxyBuyParams(TypedDict, total=False):
"""ISO 3166-1 alpha-2 country code to provision the proxy in."""
type: Required[Literal["dedicated_residential", "residential", "mobile"]]
+
+ idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")]
diff --git a/src/mobilerun_sdk/types/connect/proxy_buy_response.py b/src/mobilerun_sdk/types/connect/proxy_buy_response.py
index 403a8d80..d512bbef 100644
--- a/src/mobilerun_sdk/types/connect/proxy_buy_response.py
+++ b/src/mobilerun_sdk/types/connect/proxy_buy_response.py
@@ -27,20 +27,23 @@ class ProxyBuyResponse(BaseModel):
port: int
- status: Literal["pending_payment", "provisioning", "active", "cancelling", "ended", "error"]
+ status: Literal["checking", "pending_payment", "provisioning", "active", "cancelling", "ended", "error"]
"""Lifecycle of a proxy.
- A freshly created proxy is `provisioning` — or `pending_payment` until the
- customer completes checkout — and becomes `active` once its upstream is
- assigned. `cancelling` retains full access through the paid period; when the
- subscription expires the proxy is `ended`. `error` marks a failed provisioning
- attempt.
+ A freshly created proxy is `checking` while its billing identity is being
+ resolved — clients should poll until a `paymentUrl` or a later status appears —
+ then `provisioning` — or `pending_payment` until the customer completes checkout
+ — and becomes `active` once its upstream is assigned. `cancelling` retains full
+ access through the paid period; when the subscription expires the proxy is
+ `ended`. `error` marks a failed provisioning attempt.
"""
type: Literal["dedicated_residential", "residential", "mobile"]
username: str
+ billing_mode: Optional[Literal["included", "standalone_paid"]] = FieldInfo(alias="billingMode", default=None)
+
payment_url: Optional[str] = FieldInfo(alias="paymentUrl", default=None)
"""Checkout URL to complete payment while status is `pending_payment`.
diff --git a/src/mobilerun_sdk/types/connect/proxy_list_response.py b/src/mobilerun_sdk/types/connect/proxy_list_response.py
index 26135dca..e68fd457 100644
--- a/src/mobilerun_sdk/types/connect/proxy_list_response.py
+++ b/src/mobilerun_sdk/types/connect/proxy_list_response.py
@@ -1,6 +1,6 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import List
+from typing import List, Optional
from datetime import datetime
from typing_extensions import Literal
@@ -25,20 +25,23 @@ class Item(BaseModel):
port: int
- status: Literal["pending_payment", "provisioning", "active", "cancelling", "ended", "error"]
+ status: Literal["checking", "pending_payment", "provisioning", "active", "cancelling", "ended", "error"]
"""Lifecycle of a proxy.
- A freshly created proxy is `provisioning` — or `pending_payment` until the
- customer completes checkout — and becomes `active` once its upstream is
- assigned. `cancelling` retains full access through the paid period; when the
- subscription expires the proxy is `ended`. `error` marks a failed provisioning
- attempt.
+ A freshly created proxy is `checking` while its billing identity is being
+ resolved — clients should poll until a `paymentUrl` or a later status appears —
+ then `provisioning` — or `pending_payment` until the customer completes checkout
+ — and becomes `active` once its upstream is assigned. `cancelling` retains full
+ access through the paid period; when the subscription expires the proxy is
+ `ended`. `error` marks a failed provisioning attempt.
"""
type: Literal["dedicated_residential", "residential", "mobile"]
username: str
+ billing_mode: Optional[Literal["included", "standalone_paid"]] = FieldInfo(alias="billingMode", default=None)
+
class Pagination(BaseModel):
"""Pagination metadata for a list response."""
diff --git a/src/mobilerun_sdk/types/connect/proxy_retrieve_response.py b/src/mobilerun_sdk/types/connect/proxy_retrieve_response.py
index be8cd872..41014606 100644
--- a/src/mobilerun_sdk/types/connect/proxy_retrieve_response.py
+++ b/src/mobilerun_sdk/types/connect/proxy_retrieve_response.py
@@ -27,20 +27,23 @@ class ProxyRetrieveResponse(BaseModel):
port: int
- status: Literal["pending_payment", "provisioning", "active", "cancelling", "ended", "error"]
+ status: Literal["checking", "pending_payment", "provisioning", "active", "cancelling", "ended", "error"]
"""Lifecycle of a proxy.
- A freshly created proxy is `provisioning` — or `pending_payment` until the
- customer completes checkout — and becomes `active` once its upstream is
- assigned. `cancelling` retains full access through the paid period; when the
- subscription expires the proxy is `ended`. `error` marks a failed provisioning
- attempt.
+ A freshly created proxy is `checking` while its billing identity is being
+ resolved — clients should poll until a `paymentUrl` or a later status appears —
+ then `provisioning` — or `pending_payment` until the customer completes checkout
+ — and becomes `active` once its upstream is assigned. `cancelling` retains full
+ access through the paid period; when the subscription expires the proxy is
+ `ended`. `error` marks a failed provisioning attempt.
"""
type: Literal["dedicated_residential", "residential", "mobile"]
username: str
+ billing_mode: Optional[Literal["included", "standalone_paid"]] = FieldInfo(alias="billingMode", default=None)
+
payment_url: Optional[str] = FieldInfo(alias="paymentUrl", default=None)
"""Checkout URL to complete payment while status is `pending_payment`.
diff --git a/src/mobilerun_sdk/types/device_create_response.py b/src/mobilerun_sdk/types/device_create_response.py
index c792c9f7..307565c2 100644
--- a/src/mobilerun_sdk/types/device_create_response.py
+++ b/src/mobilerun_sdk/types/device_create_response.py
@@ -2,6 +2,7 @@
from typing import Optional
from datetime import datetime
+from typing_extensions import Literal
from pydantic import Field as FieldInfo
@@ -21,6 +22,9 @@ class DeviceCreateResponse(BaseModel):
name: str
+ platform: Literal["android", "ios"]
+ """Operating system the device runs."""
+
state: str
state_message: str = FieldInfo(alias="stateMessage")
diff --git a/src/mobilerun_sdk/types/device_list_response.py b/src/mobilerun_sdk/types/device_list_response.py
index f8c1a26a..e4c0e942 100644
--- a/src/mobilerun_sdk/types/device_list_response.py
+++ b/src/mobilerun_sdk/types/device_list_response.py
@@ -2,6 +2,7 @@
from typing import List, Optional
from datetime import datetime
+from typing_extensions import Literal
from pydantic import Field as FieldInfo
@@ -22,6 +23,9 @@ class Item(BaseModel):
name: str
+ platform: Literal["android", "ios"]
+ """Operating system the device runs."""
+
state: str
state_message: str = FieldInfo(alias="stateMessage")
diff --git a/src/mobilerun_sdk/types/device_retrieve_capabilities_response.py b/src/mobilerun_sdk/types/device_retrieve_capabilities_response.py
index 2e02c5ea..f5a6020c 100644
--- a/src/mobilerun_sdk/types/device_retrieve_capabilities_response.py
+++ b/src/mobilerun_sdk/types/device_retrieve_capabilities_response.py
@@ -42,6 +42,8 @@ class Capabilities(BaseModel):
proxy: bool
+ recording: bool
+
reset: bool
shell: bool
@@ -54,6 +56,8 @@ class Capabilities(BaseModel):
time: bool
+ traffic_inspection: bool = FieldInfo(alias="trafficInspection")
+
class DeviceRetrieveCapabilitiesResponse(BaseModel):
capabilities: Capabilities
diff --git a/src/mobilerun_sdk/types/device_retrieve_response.py b/src/mobilerun_sdk/types/device_retrieve_response.py
index 6735522c..be523d09 100644
--- a/src/mobilerun_sdk/types/device_retrieve_response.py
+++ b/src/mobilerun_sdk/types/device_retrieve_response.py
@@ -2,6 +2,7 @@
from typing import Optional
from datetime import datetime
+from typing_extensions import Literal
from pydantic import Field as FieldInfo
@@ -21,6 +22,9 @@ class DeviceRetrieveResponse(BaseModel):
name: str
+ platform: Literal["android", "ios"]
+ """Operating system the device runs."""
+
state: str
state_message: str = FieldInfo(alias="stateMessage")
diff --git a/src/mobilerun_sdk/types/device_set_name_response.py b/src/mobilerun_sdk/types/device_set_name_response.py
index f7976eea..026ac9b1 100644
--- a/src/mobilerun_sdk/types/device_set_name_response.py
+++ b/src/mobilerun_sdk/types/device_set_name_response.py
@@ -2,6 +2,7 @@
from typing import Optional
from datetime import datetime
+from typing_extensions import Literal
from pydantic import Field as FieldInfo
@@ -21,6 +22,9 @@ class DeviceSetNameResponse(BaseModel):
name: str
+ platform: Literal["android", "ios"]
+ """Operating system the device runs."""
+
state: str
state_message: str = FieldInfo(alias="stateMessage")
diff --git a/src/mobilerun_sdk/types/device_wait_ready_response.py b/src/mobilerun_sdk/types/device_wait_ready_response.py
index 73a50c61..d8de894d 100644
--- a/src/mobilerun_sdk/types/device_wait_ready_response.py
+++ b/src/mobilerun_sdk/types/device_wait_ready_response.py
@@ -2,6 +2,7 @@
from typing import Optional
from datetime import datetime
+from typing_extensions import Literal
from pydantic import Field as FieldInfo
@@ -21,6 +22,9 @@ class DeviceWaitReadyResponse(BaseModel):
name: str
+ platform: Literal["android", "ios"]
+ """Operating system the device runs."""
+
state: str
state_message: str = FieldInfo(alias="stateMessage")
diff --git a/src/mobilerun_sdk/types/devices/app_install_params.py b/src/mobilerun_sdk/types/devices/app_install_params.py
index f419dd4e..3624dc3a 100644
--- a/src/mobilerun_sdk/types/devices/app_install_params.py
+++ b/src/mobilerun_sdk/types/devices/app_install_params.py
@@ -21,9 +21,21 @@ class Variant0(TypedDict, total=False):
directly (200 on success, an error status on failure).
"""
+ country: str
+ """Optional ISO 3166-1 alpha-2 country of the uploaded app version (e.g.
+
+ MY or SG).
+ """
+
package_name: Annotated[str, PropertyInfo(alias="packageName")]
"""Android package name (e.g. com.example.app)"""
+ version_code: Annotated[int, PropertyInfo(alias="versionCode")]
+ """Optional exact app-library version code.
+
+ Use with country when multiple regional versions share an identifier.
+ """
+
x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
@@ -41,6 +53,18 @@ class Variant1(TypedDict, total=False):
bundle_id: Annotated[str, PropertyInfo(alias="bundleId")]
"""iOS bundle identifier (e.g. com.example.app)"""
+ country: str
+ """Optional ISO 3166-1 alpha-2 country of the uploaded app version (e.g.
+
+ MY or SG).
+ """
+
+ version_code: Annotated[int, PropertyInfo(alias="versionCode")]
+ """Optional exact app-library version code.
+
+ Use with country when multiple regional versions share an identifier.
+ """
+
x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun_sdk/types/devices/app_list_installs_response.py b/src/mobilerun_sdk/types/devices/app_list_installs_response.py
index 796f7b2a..ae079f10 100644
--- a/src/mobilerun_sdk/types/devices/app_list_installs_response.py
+++ b/src/mobilerun_sdk/types/devices/app_list_installs_response.py
@@ -28,11 +28,10 @@ class Install(BaseModel):
updated_at: datetime = FieldInfo(alias="updatedAt")
- error_class: Optional[str] = FieldInfo(alias="errorClass", default=None)
- """Closed set: download_failed, adb_install_failed, panic, timeout, failed.
-
- Only present when status is failed.
- """
+ error_class: Optional[Literal["download_failed", "adb_install_failed", "panic", "timeout", "failed"]] = FieldInfo(
+ alias="errorClass", default=None
+ )
+ """Only present when status is failed."""
class AppListInstallsResponse(BaseModel):
diff --git a/src/mobilerun_sdk/types/devices/keyboard_write_params.py b/src/mobilerun_sdk/types/devices/keyboard_write_params.py
index c1340d7a..7bff865f 100644
--- a/src/mobilerun_sdk/types/devices/keyboard_write_params.py
+++ b/src/mobilerun_sdk/types/devices/keyboard_write_params.py
@@ -2,7 +2,7 @@
from __future__ import annotations
-from typing_extensions import Required, Annotated, TypedDict
+from typing_extensions import Literal, Required, Annotated, TypedDict
from ..._utils import PropertyInfo
@@ -14,6 +14,14 @@ class KeyboardWriteParams(TypedDict, total=False):
clear: bool
+ completion_mode: Annotated[Literal["accepted", "committed"], PropertyInfo(alias="completionMode")]
+ """Completion guarantee.
+
+ accepted returns after the input provider accepts the operation; committed
+ additionally waits for the focused UI state to contain the complete text or
+ become quiescent.
+ """
+
error_rate: Annotated[float, PropertyInfo(alias="errorRate")]
"""Per-character mistake rate for humantouch typing. -1 uses server default."""
diff --git a/src/mobilerun_sdk/types/devices/recording_start_params.py b/src/mobilerun_sdk/types/devices/recording_start_params.py
index 621a86aa..007181d3 100644
--- a/src/mobilerun_sdk/types/devices/recording_start_params.py
+++ b/src/mobilerun_sdk/types/devices/recording_start_params.py
@@ -14,6 +14,18 @@
class RecordingStartParams(TypedDict, total=False):
name: str
+ quality: int
+ """Capture quality from 1 (lowest) to 10 (full stream quality).
+
+ Defaults to the device's full quality. Honored by devices recording through the
+ portal stream bridge.
+ """
+
retention_days: Annotated[int, PropertyInfo(alias="retentionDays")]
types: Optional[SequenceNotStr[str]]
+ """
+ Artifacts to capture: trajectory (input actions), video, and audio (captured
+ into the video artifact, so it requires video; honored by portal stream-bridge
+ recorders). Defaults to trajectory and video.
+ """
diff --git a/src/mobilerun_sdk/types/esim_capacity_response.py b/src/mobilerun_sdk/types/esim_capacity_response.py
deleted file mode 100644
index 69204004..00000000
--- a/src/mobilerun_sdk/types/esim_capacity_response.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from pydantic import Field as FieldInfo
-
-from .._models import BaseModel
-
-__all__ = ["EsimCapacityResponse", "Data"]
-
-
-class Data(BaseModel):
- available: bool
-
- free_devices: int = FieldInfo(alias="freeDevices")
-
-
-class EsimCapacityResponse(BaseModel):
- data: Data
diff --git a/src/mobilerun_sdk/types/esim_confirm_payment_response.py b/src/mobilerun_sdk/types/esim_confirm_payment_response.py
deleted file mode 100644
index d981ab88..00000000
--- a/src/mobilerun_sdk/types/esim_confirm_payment_response.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import Optional
-from datetime import datetime
-from typing_extensions import Literal
-
-from pydantic import Field as FieldInfo
-
-from .._models import BaseModel
-
-__all__ = ["EsimConfirmPaymentResponse", "Data"]
-
-
-class Data(BaseModel):
- id: str
-
- carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None)
-
- country_code: Optional[str] = FieldInfo(alias="countryCode", default=None)
-
- created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None)
-
- created_by: Optional[str] = FieldInfo(alias="createdBy", default=None)
-
- device_id: Optional[str] = FieldInfo(alias="deviceId", default=None)
-
- device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None)
-
- iccid: Optional[str] = None
-
- msisdn: Optional[str] = None
-
- name: Optional[str] = None
-
- network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None)
-
- source: Literal["stocked", "byo"]
-
- status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"]
-
- subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None)
-
- updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None)
-
- cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None)
-
- checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None)
-
- current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
-
- exempt: Optional[bool] = None
-
- rent_status: Optional[
- Literal[
- "not_applicable",
- "exempt",
- "inactive",
- "awaiting_payment",
- "active",
- "cancel_pending",
- "refund_pending",
- "retiring",
- "billing_error",
- ]
- ] = FieldInfo(alias="rentStatus", default=None)
-
-
-class EsimConfirmPaymentResponse(BaseModel):
- data: Data
diff --git a/src/mobilerun_sdk/types/esim_create_params.py b/src/mobilerun_sdk/types/esim_create_params.py
deleted file mode 100644
index 973cbd1d..00000000
--- a/src/mobilerun_sdk/types/esim_create_params.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Optional
-from typing_extensions import Annotated, TypedDict
-
-from .._utils import PropertyInfo
-
-__all__ = ["EsimCreateParams"]
-
-
-class EsimCreateParams(TypedDict, total=False):
- idempotency_key: Annotated[str, PropertyInfo(alias="idempotencyKey")]
- """
- Client-supplied key; replaying the same key returns the original purchase
- instead of buying again
- """
-
- name: Optional[str]
- """Optional user-defined display label — NFC-normalized, up to 15 GRAPHEMES.
-
- Omit or null for no label.
- """
diff --git a/src/mobilerun_sdk/types/esim_create_response.py b/src/mobilerun_sdk/types/esim_create_response.py
deleted file mode 100644
index 11111f7a..00000000
--- a/src/mobilerun_sdk/types/esim_create_response.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import Optional
-from datetime import datetime
-from typing_extensions import Literal
-
-from pydantic import Field as FieldInfo
-
-from .._models import BaseModel
-
-__all__ = ["EsimCreateResponse", "Data"]
-
-
-class Data(BaseModel):
- id: str
-
- carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None)
-
- country_code: Optional[str] = FieldInfo(alias="countryCode", default=None)
-
- created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None)
-
- created_by: Optional[str] = FieldInfo(alias="createdBy", default=None)
-
- device_id: Optional[str] = FieldInfo(alias="deviceId", default=None)
-
- device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None)
-
- iccid: Optional[str] = None
-
- msisdn: Optional[str] = None
-
- name: Optional[str] = None
-
- network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None)
-
- source: Literal["stocked", "byo"]
-
- status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"]
-
- subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None)
-
- updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None)
-
- cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None)
-
- checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None)
-
- current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
-
- exempt: Optional[bool] = None
-
- rent_status: Optional[
- Literal[
- "not_applicable",
- "exempt",
- "inactive",
- "awaiting_payment",
- "active",
- "cancel_pending",
- "refund_pending",
- "retiring",
- "billing_error",
- ]
- ] = FieldInfo(alias="rentStatus", default=None)
-
-
-class EsimCreateResponse(BaseModel):
- data: Data
diff --git a/src/mobilerun_sdk/types/esim_import_params.py b/src/mobilerun_sdk/types/esim_import_params.py
deleted file mode 100644
index 59433916..00000000
--- a/src/mobilerun_sdk/types/esim_import_params.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Optional
-from typing_extensions import Annotated, TypedDict
-
-from .._utils import PropertyInfo
-
-__all__ = ["EsimImportParams"]
-
-
-class EsimImportParams(TypedDict, total=False):
- auto_install: Annotated[bool, PropertyInfo(alias="autoInstall")]
- """Rent OFF only: dispatch install-on-device immediately after a successful import.
-
- No-op when ESIM_BYO_RENT_ENABLED=true.
- """
-
- carrier_name: Annotated[str, PropertyInfo(alias="carrierName")]
-
- confirmation_code: Annotated[str, PropertyInfo(alias="confirmationCode")]
-
- country_code: Annotated[str, PropertyInfo(alias="countryCode")]
-
- device_id: Annotated[str, PropertyInfo(alias="deviceId")]
- """physedge device id to auto-install onto; requires autoInstall:true and rent OFF.
-
- Omit for a random pool device.
- """
-
- idempotency_key: Annotated[str, PropertyInfo(alias="idempotencyKey")]
- """
- Client-supplied key; replaying the same key+request returns the original import
- instead of importing again
- """
-
- lpa_code: Annotated[str, PropertyInfo(alias="lpaCode")]
- """Full LPA activation code"""
-
- matching_id: Annotated[str, PropertyInfo(alias="matchingId")]
-
- msisdn: str
- """
- Self-reported E.164 MSISDN for this eSIM's line — an unverified label, never
- used for routing
- """
-
- name: Optional[str]
- """
- User-defined display label — NFC-normalized, up to 15 GRAPHEMES (not UTF-16 code
- units; an emoji/flag may span several). Omit/null/empty/whitespace-only leaves
- it unset.
- """
-
- notes: str
-
- smdp_address: Annotated[str, PropertyInfo(alias="smdpAddress")]
- """SM-DP+ activation host — bare hostname ONLY, no port/scheme/path."""
diff --git a/src/mobilerun_sdk/types/esim_import_response.py b/src/mobilerun_sdk/types/esim_import_response.py
deleted file mode 100644
index 5ab93dba..00000000
--- a/src/mobilerun_sdk/types/esim_import_response.py
+++ /dev/null
@@ -1,204 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import Union, Optional
-from datetime import datetime
-from typing_extensions import Literal, TypeAlias
-
-from pydantic import Field as FieldInfo
-
-from .._models import BaseModel
-
-__all__ = [
- "EsimImportResponse",
- "Data",
- "DataPublicEsim",
- "DataEsimAwaitingPaymentResponse",
- "DataEsimAwaitingPaymentResponseEsim",
- "DataEsimImportInstallDispatchFailedResponse",
- "DataEsimImportInstallDispatchFailedResponseInstallDispatch",
-]
-
-
-class DataPublicEsim(BaseModel):
- id: str
-
- carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None)
-
- country_code: Optional[str] = FieldInfo(alias="countryCode", default=None)
-
- created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None)
-
- created_by: Optional[str] = FieldInfo(alias="createdBy", default=None)
-
- device_id: Optional[str] = FieldInfo(alias="deviceId", default=None)
-
- device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None)
-
- iccid: Optional[str] = None
-
- msisdn: Optional[str] = None
-
- name: Optional[str] = None
-
- network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None)
-
- source: Literal["stocked", "byo"]
-
- status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"]
-
- subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None)
-
- updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None)
-
- cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None)
-
- checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None)
-
- current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
-
- exempt: Optional[bool] = None
-
- rent_status: Optional[
- Literal[
- "not_applicable",
- "exempt",
- "inactive",
- "awaiting_payment",
- "active",
- "cancel_pending",
- "refund_pending",
- "retiring",
- "billing_error",
- ]
- ] = FieldInfo(alias="rentStatus", default=None)
-
-
-class DataEsimAwaitingPaymentResponseEsim(BaseModel):
- id: str
-
- carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None)
-
- country_code: Optional[str] = FieldInfo(alias="countryCode", default=None)
-
- created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None)
-
- created_by: Optional[str] = FieldInfo(alias="createdBy", default=None)
-
- device_id: Optional[str] = FieldInfo(alias="deviceId", default=None)
-
- device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None)
-
- iccid: Optional[str] = None
-
- msisdn: Optional[str] = None
-
- name: Optional[str] = None
-
- network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None)
-
- source: Literal["stocked", "byo"]
-
- status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"]
-
- subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None)
-
- updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None)
-
- cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None)
-
- checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None)
-
- current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
-
- exempt: Optional[bool] = None
-
- rent_status: Optional[
- Literal[
- "not_applicable",
- "exempt",
- "inactive",
- "awaiting_payment",
- "active",
- "cancel_pending",
- "refund_pending",
- "retiring",
- "billing_error",
- ]
- ] = FieldInfo(alias="rentStatus", default=None)
-
-
-class DataEsimAwaitingPaymentResponse(BaseModel):
- checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None)
-
- esim: DataEsimAwaitingPaymentResponseEsim
-
- rent_status: Literal["awaiting_payment"] = FieldInfo(alias="rentStatus")
-
-
-class DataEsimImportInstallDispatchFailedResponseInstallDispatch(BaseModel):
- ok: Literal[False]
-
- reason: str
-
-
-class DataEsimImportInstallDispatchFailedResponse(BaseModel):
- id: str
-
- carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None)
-
- country_code: Optional[str] = FieldInfo(alias="countryCode", default=None)
-
- created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None)
-
- created_by: Optional[str] = FieldInfo(alias="createdBy", default=None)
-
- device_id: Optional[str] = FieldInfo(alias="deviceId", default=None)
-
- device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None)
-
- iccid: Optional[str] = None
-
- install_dispatch: DataEsimImportInstallDispatchFailedResponseInstallDispatch = FieldInfo(alias="installDispatch")
-
- msisdn: Optional[str] = None
-
- name: Optional[str] = None
-
- network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None)
-
- source: Literal["stocked", "byo"]
-
- status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"]
-
- subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None)
-
- updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None)
-
- cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None)
-
- checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None)
-
- current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
-
- exempt: Optional[bool] = None
-
- rent_status: Optional[
- Literal[
- "not_applicable",
- "exempt",
- "inactive",
- "awaiting_payment",
- "active",
- "cancel_pending",
- "refund_pending",
- "retiring",
- "billing_error",
- ]
- ] = FieldInfo(alias="rentStatus", default=None)
-
-
-Data: TypeAlias = Union[DataPublicEsim, DataEsimAwaitingPaymentResponse, DataEsimImportInstallDispatchFailedResponse]
-
-
-class EsimImportResponse(BaseModel):
- data: Data
diff --git a/src/mobilerun_sdk/types/esim_install_params.py b/src/mobilerun_sdk/types/esim_install_params.py
deleted file mode 100644
index ca23a433..00000000
--- a/src/mobilerun_sdk/types/esim_install_params.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Annotated, TypedDict
-
-from .._utils import PropertyInfo
-
-__all__ = ["EsimInstallParams"]
-
-
-class EsimInstallParams(TypedDict, total=False):
- device_id: Annotated[str, PropertyInfo(alias="deviceId")]
- """physedge device id to install the eSIM onto; omit for a random pool device"""
diff --git a/src/mobilerun_sdk/types/esim_install_response.py b/src/mobilerun_sdk/types/esim_install_response.py
deleted file mode 100644
index 24ea2f92..00000000
--- a/src/mobilerun_sdk/types/esim_install_response.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import Optional
-from datetime import datetime
-from typing_extensions import Literal
-
-from pydantic import Field as FieldInfo
-
-from .._models import BaseModel
-
-__all__ = ["EsimInstallResponse", "Data"]
-
-
-class Data(BaseModel):
- id: str
-
- carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None)
-
- country_code: Optional[str] = FieldInfo(alias="countryCode", default=None)
-
- created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None)
-
- created_by: Optional[str] = FieldInfo(alias="createdBy", default=None)
-
- device_id: Optional[str] = FieldInfo(alias="deviceId", default=None)
-
- device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None)
-
- iccid: Optional[str] = None
-
- msisdn: Optional[str] = None
-
- name: Optional[str] = None
-
- network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None)
-
- source: Literal["stocked", "byo"]
-
- status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"]
-
- subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None)
-
- updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None)
-
- cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None)
-
- checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None)
-
- current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
-
- exempt: Optional[bool] = None
-
- rent_status: Optional[
- Literal[
- "not_applicable",
- "exempt",
- "inactive",
- "awaiting_payment",
- "active",
- "cancel_pending",
- "refund_pending",
- "retiring",
- "billing_error",
- ]
- ] = FieldInfo(alias="rentStatus", default=None)
-
-
-class EsimInstallResponse(BaseModel):
- data: Data
diff --git a/src/mobilerun_sdk/types/esim_install_status_response.py b/src/mobilerun_sdk/types/esim_install_status_response.py
deleted file mode 100644
index 87f8c3e5..00000000
--- a/src/mobilerun_sdk/types/esim_install_status_response.py
+++ /dev/null
@@ -1,93 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import Optional
-from datetime import datetime
-from typing_extensions import Literal
-
-from pydantic import Field as FieldInfo
-
-from .._models import BaseModel
-
-__all__ = ["EsimInstallStatusResponse", "Data", "DataEsim"]
-
-
-class DataEsim(BaseModel):
- id: str
-
- carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None)
-
- country_code: Optional[str] = FieldInfo(alias="countryCode", default=None)
-
- created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None)
-
- created_by: Optional[str] = FieldInfo(alias="createdBy", default=None)
-
- device_id: Optional[str] = FieldInfo(alias="deviceId", default=None)
-
- device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None)
-
- iccid: Optional[str] = None
-
- msisdn: Optional[str] = None
-
- name: Optional[str] = None
-
- network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None)
-
- source: Literal["stocked", "byo"]
-
- status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"]
-
- subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None)
-
- updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None)
-
- cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None)
-
- checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None)
-
- current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
-
- exempt: Optional[bool] = None
-
- rent_status: Optional[
- Literal[
- "not_applicable",
- "exempt",
- "inactive",
- "awaiting_payment",
- "active",
- "cancel_pending",
- "refund_pending",
- "retiring",
- "billing_error",
- ]
- ] = FieldInfo(alias="rentStatus", default=None)
-
-
-class Data(BaseModel):
- esim: DataEsim
-
- operation_id: Optional[str] = FieldInfo(alias="operationId", default=None)
-
- status: Optional[
- Literal[
- "installing",
- "pending_download",
- "downloading",
- "downloaded",
- "enabling",
- "configuring_apn",
- "active",
- "download_failed",
- "enable_failed",
- "download_outcome_unknown",
- "install_failed",
- "physical_removal_unconfirmed",
- "deleted",
- ]
- ] = None
-
-
-class EsimInstallStatusResponse(BaseModel):
- data: Data
diff --git a/src/mobilerun_sdk/types/esim_list_params.py b/src/mobilerun_sdk/types/esim_list_params.py
deleted file mode 100644
index a653308b..00000000
--- a/src/mobilerun_sdk/types/esim_list_params.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Literal, Annotated, TypedDict
-
-from .._utils import PropertyInfo
-
-__all__ = ["EsimListParams"]
-
-
-class EsimListParams(TypedDict, total=False):
- mine: Literal["true", "false"]
- """Only include eSIMs created by the calling actor."""
-
- page: int
-
- page_size: Annotated[int, PropertyInfo(alias="pageSize")]
-
- status: Literal["all", "in_stock", "owned", "installing", "installed", "install_failed", "retired"]
diff --git a/src/mobilerun_sdk/types/esim_list_response.py b/src/mobilerun_sdk/types/esim_list_response.py
deleted file mode 100644
index 5c236e21..00000000
--- a/src/mobilerun_sdk/types/esim_list_response.py
+++ /dev/null
@@ -1,72 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import List, Optional
-from datetime import datetime
-from typing_extensions import Literal
-
-from pydantic import Field as FieldInfo
-
-from .._models import BaseModel
-from .shared.pagination import Pagination
-
-__all__ = ["EsimListResponse", "Item"]
-
-
-class Item(BaseModel):
- id: str
-
- carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None)
-
- country_code: Optional[str] = FieldInfo(alias="countryCode", default=None)
-
- created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None)
-
- created_by: Optional[str] = FieldInfo(alias="createdBy", default=None)
-
- device_id: Optional[str] = FieldInfo(alias="deviceId", default=None)
-
- device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None)
-
- iccid: Optional[str] = None
-
- msisdn: Optional[str] = None
-
- name: Optional[str] = None
-
- network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None)
-
- source: Literal["stocked", "byo"]
-
- status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"]
-
- subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None)
-
- updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None)
-
- cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None)
-
- checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None)
-
- current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
-
- exempt: Optional[bool] = None
-
- rent_status: Optional[
- Literal[
- "not_applicable",
- "exempt",
- "inactive",
- "awaiting_payment",
- "active",
- "cancel_pending",
- "refund_pending",
- "retiring",
- "billing_error",
- ]
- ] = FieldInfo(alias="rentStatus", default=None)
-
-
-class EsimListResponse(BaseModel):
- items: List[Item]
-
- pagination: Pagination
diff --git a/src/mobilerun_sdk/types/esim_retrieve_response.py b/src/mobilerun_sdk/types/esim_retrieve_response.py
deleted file mode 100644
index 41cf5a88..00000000
--- a/src/mobilerun_sdk/types/esim_retrieve_response.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import Optional
-from datetime import datetime
-from typing_extensions import Literal
-
-from pydantic import Field as FieldInfo
-
-from .._models import BaseModel
-
-__all__ = ["EsimRetrieveResponse", "Data"]
-
-
-class Data(BaseModel):
- id: str
-
- carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None)
-
- country_code: Optional[str] = FieldInfo(alias="countryCode", default=None)
-
- created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None)
-
- created_by: Optional[str] = FieldInfo(alias="createdBy", default=None)
-
- device_id: Optional[str] = FieldInfo(alias="deviceId", default=None)
-
- device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None)
-
- iccid: Optional[str] = None
-
- msisdn: Optional[str] = None
-
- name: Optional[str] = None
-
- network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None)
-
- source: Literal["stocked", "byo"]
-
- status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"]
-
- subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None)
-
- updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None)
-
- cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None)
-
- checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None)
-
- current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
-
- exempt: Optional[bool] = None
-
- rent_status: Optional[
- Literal[
- "not_applicable",
- "exempt",
- "inactive",
- "awaiting_payment",
- "active",
- "cancel_pending",
- "refund_pending",
- "retiring",
- "billing_error",
- ]
- ] = FieldInfo(alias="rentStatus", default=None)
-
-
-class EsimRetrieveResponse(BaseModel):
- data: Data
diff --git a/src/mobilerun_sdk/types/esim_selector_params.py b/src/mobilerun_sdk/types/esim_selector_params.py
deleted file mode 100644
index d5cd46c1..00000000
--- a/src/mobilerun_sdk/types/esim_selector_params.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Annotated, TypedDict
-
-from .._utils import PropertyInfo
-
-__all__ = ["EsimSelectorParams"]
-
-
-class EsimSelectorParams(TypedDict, total=False):
- page: int
-
- page_size: Annotated[int, PropertyInfo(alias="pageSize")]
diff --git a/src/mobilerun_sdk/types/esim_selector_response.py b/src/mobilerun_sdk/types/esim_selector_response.py
deleted file mode 100644
index 4288bcf9..00000000
--- a/src/mobilerun_sdk/types/esim_selector_response.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import List, Optional
-from typing_extensions import Literal
-
-from pydantic import Field as FieldInfo
-
-from .._models import BaseModel
-from .shared.pagination import Pagination
-
-__all__ = ["EsimSelectorResponse", "Item"]
-
-
-class Item(BaseModel):
- id: str
-
- carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None)
-
- iccid: Optional[str] = None
-
- msisdn: Optional[str] = None
-
- name: Optional[str] = None
-
- source: Literal["stocked", "byo"]
-
- status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"]
-
-
-class EsimSelectorResponse(BaseModel):
- items: List[Item]
-
- pagination: Pagination
diff --git a/src/mobilerun_sdk/types/esim_update_params.py b/src/mobilerun_sdk/types/esim_update_params.py
deleted file mode 100644
index a0fdc6de..00000000
--- a/src/mobilerun_sdk/types/esim_update_params.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Optional
-from typing_extensions import TypedDict
-
-__all__ = ["EsimUpdateParams"]
-
-
-class EsimUpdateParams(TypedDict, total=False):
- msisdn: Optional[str]
- """Self-reported E.164 MSISDN for this eSIM's line.
-
- Omit to leave unchanged; null/empty clears it. An unverified label — never used
- for routing.
- """
-
- name: Optional[str]
- """
- User-defined display label — NFC-normalized, up to 15 GRAPHEMES (not UTF-16 code
- units; an emoji/flag may span several). Omit to leave unchanged;
- null/empty/whitespace-only clears it.
- """
diff --git a/src/mobilerun_sdk/types/esim_update_response.py b/src/mobilerun_sdk/types/esim_update_response.py
deleted file mode 100644
index 407eb7d9..00000000
--- a/src/mobilerun_sdk/types/esim_update_response.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import Optional
-from datetime import datetime
-from typing_extensions import Literal
-
-from pydantic import Field as FieldInfo
-
-from .._models import BaseModel
-
-__all__ = ["EsimUpdateResponse", "Data"]
-
-
-class Data(BaseModel):
- id: str
-
- carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None)
-
- country_code: Optional[str] = FieldInfo(alias="countryCode", default=None)
-
- created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None)
-
- created_by: Optional[str] = FieldInfo(alias="createdBy", default=None)
-
- device_id: Optional[str] = FieldInfo(alias="deviceId", default=None)
-
- device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None)
-
- iccid: Optional[str] = None
-
- msisdn: Optional[str] = None
-
- name: Optional[str] = None
-
- network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None)
-
- source: Literal["stocked", "byo"]
-
- status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"]
-
- subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None)
-
- updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None)
-
- cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None)
-
- checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None)
-
- current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
-
- exempt: Optional[bool] = None
-
- rent_status: Optional[
- Literal[
- "not_applicable",
- "exempt",
- "inactive",
- "awaiting_payment",
- "active",
- "cancel_pending",
- "refund_pending",
- "retiring",
- "billing_error",
- ]
- ] = FieldInfo(alias="rentStatus", default=None)
-
-
-class EsimUpdateResponse(BaseModel):
- data: Data
diff --git a/src/mobilerun_sdk/types/esims/__init__.py b/src/mobilerun_sdk/types/esims/__init__.py
index d059c99c..f8ee8b14 100644
--- a/src/mobilerun_sdk/types/esims/__init__.py
+++ b/src/mobilerun_sdk/types/esims/__init__.py
@@ -1,8 +1,3 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
-
-from .message_list_params import MessageListParams as MessageListParams
-from .message_send_params import MessageSendParams as MessageSendParams
-from .message_list_response import MessageListResponse as MessageListResponse
-from .message_send_response import MessageSendResponse as MessageSendResponse
diff --git a/src/mobilerun_sdk/types/esims/message_list_params.py b/src/mobilerun_sdk/types/esims/message_list_params.py
deleted file mode 100644
index c55e68af..00000000
--- a/src/mobilerun_sdk/types/esims/message_list_params.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Literal, Annotated, TypedDict
-
-from ..._utils import PropertyInfo
-
-__all__ = ["MessageListParams"]
-
-
-class MessageListParams(TypedDict, total=False):
- direction: Literal["all", "inbound", "outbound"]
-
- number_id: Annotated[str, PropertyInfo(alias="numberId")]
-
- page: int
-
- page_size: Annotated[int, PropertyInfo(alias="pageSize")]
-
- peer_key: Annotated[str, PropertyInfo(alias="peerKey")]
-
- peer_number: Annotated[str, PropertyInfo(alias="peerNumber")]
-
- status: Literal[
- "all", "received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed"
- ]
diff --git a/src/mobilerun_sdk/types/esims/message_list_response.py b/src/mobilerun_sdk/types/esims/message_list_response.py
deleted file mode 100644
index c04b3d46..00000000
--- a/src/mobilerun_sdk/types/esims/message_list_response.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import List, Optional
-from datetime import datetime
-from typing_extensions import Literal
-
-from pydantic import Field as FieldInfo
-
-from ..._models import BaseModel
-from ..shared.pagination import Pagination
-
-__all__ = ["MessageListResponse", "Item"]
-
-
-class Item(BaseModel):
- id: str
-
- body: Optional[str] = None
-
- created_at: datetime = FieldInfo(alias="createdAt")
-
- delivery_status: Optional[str] = FieldInfo(alias="deliveryStatus", default=None)
-
- detected_sender: Optional[str] = FieldInfo(alias="detectedSender", default=None)
-
- direction: Literal["inbound", "outbound"]
-
- esim_id: Optional[str] = FieldInfo(alias="esimId", default=None)
-
- occurred_at: datetime = FieldInfo(alias="occurredAt")
-
- peer_key: Optional[str] = FieldInfo(alias="peerKey", default=None)
-
- peer_number: Optional[str] = FieldInfo(alias="peerNumber", default=None)
-
- provider_code: Optional[str] = FieldInfo(alias="providerCode", default=None)
-
- status: Literal["received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed"]
-
-
-class MessageListResponse(BaseModel):
- items: List[Item]
-
- pagination: Pagination
diff --git a/src/mobilerun_sdk/types/esims/message_send_params.py b/src/mobilerun_sdk/types/esims/message_send_params.py
deleted file mode 100644
index 48c2c65a..00000000
--- a/src/mobilerun_sdk/types/esims/message_send_params.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Required, Annotated, TypedDict
-
-from ..._utils import PropertyInfo
-
-__all__ = ["MessageSendParams"]
-
-
-class MessageSendParams(TypedDict, total=False):
- body: Required[str]
- """
- SMS body text (max 320 chars — smaller than the admin tier's cap; see the
- schema's own doc comment for why)
- """
-
- to: Required[str]
- """
- Recipient phone number — normalized to E.164 (spaces/dashes/dots stripped);
- rejected with 400 if it doesn't validate as E.164 afterward.
- """
-
- client_request_id: Annotated[str, PropertyInfo(alias="clientRequestId")]
- """Client-supplied idempotency key, scoped to (owner, esimId, key).
-
- Replaying the same key + identical payload returns the original send; the same
- key with a DIFFERENT payload is a 409 conflict.
- """
-
- delivery_report: Annotated[bool, PropertyInfo(alias="deliveryReport")]
- """
- Wait for physedge to confirm carrier delivery before completing the send (adds
- executor-side latency, never on this request — sends are always async/202).
- Defaults to false for the public tier (opt-in, unlike the admin tier's
- default-true).
- """
diff --git a/src/mobilerun_sdk/types/esims/message_send_response.py b/src/mobilerun_sdk/types/esims/message_send_response.py
deleted file mode 100644
index 86e545d6..00000000
--- a/src/mobilerun_sdk/types/esims/message_send_response.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import Optional
-from datetime import datetime
-from typing_extensions import Literal
-
-from pydantic import Field as FieldInfo
-
-from ..._models import BaseModel
-
-__all__ = ["MessageSendResponse", "Data"]
-
-
-class Data(BaseModel):
- id: str
-
- body: Optional[str] = None
-
- created_at: datetime = FieldInfo(alias="createdAt")
-
- delivery_status: Optional[str] = FieldInfo(alias="deliveryStatus", default=None)
-
- detected_sender: Optional[str] = FieldInfo(alias="detectedSender", default=None)
-
- direction: Literal["inbound", "outbound"]
-
- esim_id: Optional[str] = FieldInfo(alias="esimId", default=None)
-
- occurred_at: datetime = FieldInfo(alias="occurredAt")
-
- peer_key: Optional[str] = FieldInfo(alias="peerKey", default=None)
-
- peer_number: Optional[str] = FieldInfo(alias="peerNumber", default=None)
-
- provider_code: Optional[str] = FieldInfo(alias="providerCode", default=None)
-
- status: Literal["received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed"]
-
-
-class MessageSendResponse(BaseModel):
- data: Data
diff --git a/src/mobilerun_sdk/types/file_confirm_response.py b/src/mobilerun_sdk/types/file_confirm_response.py
index 7ee2a30c..70ee1b74 100644
--- a/src/mobilerun_sdk/types/file_confirm_response.py
+++ b/src/mobilerun_sdk/types/file_confirm_response.py
@@ -1,14 +1,55 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import Optional
+from typing import Union, Optional
from datetime import datetime
-from typing_extensions import Literal
+from typing_extensions import Literal, TypeAlias
from pydantic import Field as FieldInfo
from .._models import BaseModel
-__all__ = ["FileConfirmResponse"]
+__all__ = [
+ "FileConfirmResponse",
+ "CollectionStatus",
+ "CollectionStatusUnionMember0",
+ "CollectionStatusUnionMember0Records",
+ "CollectionStatusUnionMember1",
+]
+
+
+class CollectionStatusUnionMember0Records(BaseModel):
+ reported: int
+
+ unit: str
+
+
+class CollectionStatusUnionMember0(BaseModel):
+ completeness: Literal["complete", "partial", "none", "unknown"]
+
+ coverage: Literal["exhaustive", "bounded", "unknown"]
+
+ end_reached: bool = FieldInfo(alias="endReached")
+
+ records: CollectionStatusUnionMember0Records
+
+ resumable: bool
+
+ version: Literal[1]
+
+
+class CollectionStatusUnionMember1(BaseModel):
+ completeness: Literal["unknown"]
+
+ coverage: Literal["unknown"]
+
+ end_reached: Literal[False] = FieldInfo(alias="endReached")
+
+ resumable: Literal[False]
+
+ version: Literal[1]
+
+
+CollectionStatus: TypeAlias = Union[CollectionStatusUnionMember0, CollectionStatusUnionMember1]
class FileConfirmResponse(BaseModel):
@@ -33,3 +74,5 @@ class FileConfirmResponse(BaseModel):
state: Literal["ready"]
zone: Literal["user", "agent", "workflow", "skills"]
+
+ collection_status: Optional[CollectionStatus] = FieldInfo(alias="collectionStatus", default=None)
diff --git a/src/mobilerun_sdk/types/file_list_response.py b/src/mobilerun_sdk/types/file_list_response.py
index 014c11fb..b3ccd796 100644
--- a/src/mobilerun_sdk/types/file_list_response.py
+++ b/src/mobilerun_sdk/types/file_list_response.py
@@ -1,14 +1,57 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import List, Optional
+from typing import List, Union, Optional
from datetime import datetime
-from typing_extensions import Literal
+from typing_extensions import Literal, TypeAlias
from pydantic import Field as FieldInfo
from .._models import BaseModel
-__all__ = ["FileListResponse", "File", "Quota"]
+__all__ = [
+ "FileListResponse",
+ "File",
+ "FileCollectionStatus",
+ "FileCollectionStatusUnionMember0",
+ "FileCollectionStatusUnionMember0Records",
+ "FileCollectionStatusUnionMember1",
+ "Quota",
+]
+
+
+class FileCollectionStatusUnionMember0Records(BaseModel):
+ reported: int
+
+ unit: str
+
+
+class FileCollectionStatusUnionMember0(BaseModel):
+ completeness: Literal["complete", "partial", "none", "unknown"]
+
+ coverage: Literal["exhaustive", "bounded", "unknown"]
+
+ end_reached: bool = FieldInfo(alias="endReached")
+
+ records: FileCollectionStatusUnionMember0Records
+
+ resumable: bool
+
+ version: Literal[1]
+
+
+class FileCollectionStatusUnionMember1(BaseModel):
+ completeness: Literal["unknown"]
+
+ coverage: Literal["unknown"]
+
+ end_reached: Literal[False] = FieldInfo(alias="endReached")
+
+ resumable: Literal[False]
+
+ version: Literal[1]
+
+
+FileCollectionStatus: TypeAlias = Union[FileCollectionStatusUnionMember0, FileCollectionStatusUnionMember1]
class File(BaseModel):
@@ -30,6 +73,8 @@ class File(BaseModel):
zone: Literal["user", "agent", "workflow", "skills"]
+ collection_status: Optional[FileCollectionStatus] = FieldInfo(alias="collectionStatus", default=None)
+
class Quota(BaseModel):
current_bytes: int = FieldInfo(alias="currentBytes")
diff --git a/src/mobilerun_sdk/types/file_update_response.py b/src/mobilerun_sdk/types/file_update_response.py
index a3903256..e9f21496 100644
--- a/src/mobilerun_sdk/types/file_update_response.py
+++ b/src/mobilerun_sdk/types/file_update_response.py
@@ -1,14 +1,55 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import Optional
+from typing import Union, Optional
from datetime import datetime
-from typing_extensions import Literal
+from typing_extensions import Literal, TypeAlias
from pydantic import Field as FieldInfo
from .._models import BaseModel
-__all__ = ["FileUpdateResponse"]
+__all__ = [
+ "FileUpdateResponse",
+ "CollectionStatus",
+ "CollectionStatusUnionMember0",
+ "CollectionStatusUnionMember0Records",
+ "CollectionStatusUnionMember1",
+]
+
+
+class CollectionStatusUnionMember0Records(BaseModel):
+ reported: int
+
+ unit: str
+
+
+class CollectionStatusUnionMember0(BaseModel):
+ completeness: Literal["complete", "partial", "none", "unknown"]
+
+ coverage: Literal["exhaustive", "bounded", "unknown"]
+
+ end_reached: bool = FieldInfo(alias="endReached")
+
+ records: CollectionStatusUnionMember0Records
+
+ resumable: bool
+
+ version: Literal[1]
+
+
+class CollectionStatusUnionMember1(BaseModel):
+ completeness: Literal["unknown"]
+
+ coverage: Literal["unknown"]
+
+ end_reached: Literal[False] = FieldInfo(alias="endReached")
+
+ resumable: Literal[False]
+
+ version: Literal[1]
+
+
+CollectionStatus: TypeAlias = Union[CollectionStatusUnionMember0, CollectionStatusUnionMember1]
class FileUpdateResponse(BaseModel):
@@ -29,3 +70,5 @@ class FileUpdateResponse(BaseModel):
size_bytes: float = FieldInfo(alias="sizeBytes")
zone: Literal["user", "agent", "workflow", "skills"]
+
+ collection_status: Optional[CollectionStatus] = FieldInfo(alias="collectionStatus", default=None)
diff --git a/src/mobilerun_sdk/types/mailbox_capacity_response.py b/src/mobilerun_sdk/types/mailbox_capacity_response.py
index 9ca87175..ddeeab6b 100644
--- a/src/mobilerun_sdk/types/mailbox_capacity_response.py
+++ b/src/mobilerun_sdk/types/mailbox_capacity_response.py
@@ -1,5 +1,7 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+from typing_extensions import Literal
+
from pydantic import Field as FieldInfo
from .._models import BaseModel
@@ -8,8 +10,14 @@
class Data(BaseModel):
+ included: int
+
included_remaining: int = FieldInfo(alias="includedRemaining")
+ remaining: int
+
+ status: Literal["available", "exhausted", "not_included"]
+
class MailboxCapacityResponse(BaseModel):
data: Data
diff --git a/src/mobilerun_sdk/types/mailbox_create_params.py b/src/mobilerun_sdk/types/mailbox_create_params.py
index bd5b7ce5..68cf68f8 100644
--- a/src/mobilerun_sdk/types/mailbox_create_params.py
+++ b/src/mobilerun_sdk/types/mailbox_create_params.py
@@ -12,18 +12,20 @@
class MailboxCreateParams(TypedDict, total=False):
client_request_id: Required[Annotated[str, PropertyInfo(alias="clientRequestId")]]
- billing_preference: Annotated[Literal["included", "rent"], PropertyInfo(alias="billingPreference")]
- """Funding preference.
+ billing_preference: Annotated[Literal["included", "included_only", "rent"], PropertyInfo(alias="billingPreference")]
+ """
+ included uses package capacity when available and otherwise starts paid
+ checkout; included_only fails without creating a paid reservation when no
+ included slot remains; rent always starts paid checkout.
+ """
+
+ domain_id: Annotated[str, PropertyInfo(alias="domainId")]
+ """Optional active custom mailbox domain owned by the caller.
- Omit or use included for included-first activation; rent always preserves
- package capacity and starts paid checkout.
+ Omit to use the system domain.
"""
label: str
local_part: Annotated[str, PropertyInfo(alias="localPart")]
- """Optional full mailbox local part (the address before "@").
-
- Trimmed and lowercased before validation. Omit for a random, non-guessable
- mx\\__-prefixed address.
- """
+ """Optional mailbox name before the "@". Omit to generate a random address."""
diff --git a/src/mobilerun_sdk/types/mailbox_create_response.py b/src/mobilerun_sdk/types/mailbox_create_response.py
index 0ed4e6c4..2bb8b3c9 100644
--- a/src/mobilerun_sdk/types/mailbox_create_response.py
+++ b/src/mobilerun_sdk/types/mailbox_create_response.py
@@ -26,7 +26,7 @@ class Data(BaseModel):
address: Optional[str] = None
- billing_mode: Literal["rent", "included"] = FieldInfo(alias="billingMode")
+ billing_mode: Literal["rent", "included", "domain"] = FieldInfo(alias="billingMode")
cancel_at_period_end: bool = FieldInfo(alias="cancelAtPeriodEnd")
@@ -38,6 +38,8 @@ class Data(BaseModel):
current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
+ domain_id: Optional[str] = FieldInfo(alias="domainId", default=None)
+
inbound_messages: DataInboundMessages = FieldInfo(alias="inboundMessages")
label: Optional[str] = None
diff --git a/src/mobilerun_sdk/types/mailbox_delete_response.py b/src/mobilerun_sdk/types/mailbox_delete_response.py
index 7b6675cd..ac6cd9b8 100644
--- a/src/mobilerun_sdk/types/mailbox_delete_response.py
+++ b/src/mobilerun_sdk/types/mailbox_delete_response.py
@@ -26,7 +26,7 @@ class Data(BaseModel):
address: Optional[str] = None
- billing_mode: Literal["rent", "included"] = FieldInfo(alias="billingMode")
+ billing_mode: Literal["rent", "included", "domain"] = FieldInfo(alias="billingMode")
cancel_at_period_end: bool = FieldInfo(alias="cancelAtPeriodEnd")
@@ -38,6 +38,8 @@ class Data(BaseModel):
current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
+ domain_id: Optional[str] = FieldInfo(alias="domainId", default=None)
+
inbound_messages: DataInboundMessages = FieldInfo(alias="inboundMessages")
label: Optional[str] = None
diff --git a/src/mobilerun_sdk/types/mailbox_list_response.py b/src/mobilerun_sdk/types/mailbox_list_response.py
index df935fc8..70ace920 100644
--- a/src/mobilerun_sdk/types/mailbox_list_response.py
+++ b/src/mobilerun_sdk/types/mailbox_list_response.py
@@ -27,7 +27,7 @@ class Item(BaseModel):
address: Optional[str] = None
- billing_mode: Literal["rent", "included"] = FieldInfo(alias="billingMode")
+ billing_mode: Literal["rent", "included", "domain"] = FieldInfo(alias="billingMode")
cancel_at_period_end: bool = FieldInfo(alias="cancelAtPeriodEnd")
@@ -39,6 +39,8 @@ class Item(BaseModel):
current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
+ domain_id: Optional[str] = FieldInfo(alias="domainId", default=None)
+
inbound_messages: ItemInboundMessages = FieldInfo(alias="inboundMessages")
label: Optional[str] = None
diff --git a/src/mobilerun_sdk/types/mailbox_otp_response.py b/src/mobilerun_sdk/types/mailbox_otp_response.py
index 28ce8f48..540069ac 100644
--- a/src/mobilerun_sdk/types/mailbox_otp_response.py
+++ b/src/mobilerun_sdk/types/mailbox_otp_response.py
@@ -13,7 +13,7 @@
class Data(BaseModel):
code: str
- """String to preserve leading zeros"""
+ """OTP code as text to preserve leading zeros."""
confidence: Literal["high", "medium", "low"]
diff --git a/src/mobilerun_sdk/types/mailbox_restart_params.py b/src/mobilerun_sdk/types/mailbox_restart_params.py
index 497bb7e0..ca174720 100644
--- a/src/mobilerun_sdk/types/mailbox_restart_params.py
+++ b/src/mobilerun_sdk/types/mailbox_restart_params.py
@@ -10,9 +10,9 @@
class MailboxRestartParams(TypedDict, total=False):
- billing_preference: Annotated[Literal["included", "rent"], PropertyInfo(alias="billingPreference")]
- """Funding preference.
-
- Omit or use included for included-first activation; rent always preserves
- package capacity and starts paid checkout.
+ billing_preference: Annotated[Literal["included", "included_only", "rent"], PropertyInfo(alias="billingPreference")]
+ """
+ included uses package capacity when available and otherwise starts paid
+ checkout; included_only fails without creating a paid reservation when no
+ included slot remains; rent always starts paid checkout.
"""
diff --git a/src/mobilerun_sdk/types/mailbox_restart_response.py b/src/mobilerun_sdk/types/mailbox_restart_response.py
index 4bef7939..ab9e1d79 100644
--- a/src/mobilerun_sdk/types/mailbox_restart_response.py
+++ b/src/mobilerun_sdk/types/mailbox_restart_response.py
@@ -26,7 +26,7 @@ class Data(BaseModel):
address: Optional[str] = None
- billing_mode: Literal["rent", "included"] = FieldInfo(alias="billingMode")
+ billing_mode: Literal["rent", "included", "domain"] = FieldInfo(alias="billingMode")
cancel_at_period_end: bool = FieldInfo(alias="cancelAtPeriodEnd")
@@ -38,6 +38,8 @@ class Data(BaseModel):
current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
+ domain_id: Optional[str] = FieldInfo(alias="domainId", default=None)
+
inbound_messages: DataInboundMessages = FieldInfo(alias="inboundMessages")
label: Optional[str] = None
diff --git a/src/mobilerun_sdk/types/mailbox_retrieve_response.py b/src/mobilerun_sdk/types/mailbox_retrieve_response.py
index efb60e24..ed490495 100644
--- a/src/mobilerun_sdk/types/mailbox_retrieve_response.py
+++ b/src/mobilerun_sdk/types/mailbox_retrieve_response.py
@@ -26,7 +26,7 @@ class Data(BaseModel):
address: Optional[str] = None
- billing_mode: Literal["rent", "included"] = FieldInfo(alias="billingMode")
+ billing_mode: Literal["rent", "included", "domain"] = FieldInfo(alias="billingMode")
cancel_at_period_end: bool = FieldInfo(alias="cancelAtPeriodEnd")
@@ -38,6 +38,8 @@ class Data(BaseModel):
current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
+ domain_id: Optional[str] = FieldInfo(alias="domainId", default=None)
+
inbound_messages: DataInboundMessages = FieldInfo(alias="inboundMessages")
label: Optional[str] = None
diff --git a/src/mobilerun_sdk/types/mailbox_uncancel_response.py b/src/mobilerun_sdk/types/mailbox_uncancel_response.py
index 04688b3b..fc6b588e 100644
--- a/src/mobilerun_sdk/types/mailbox_uncancel_response.py
+++ b/src/mobilerun_sdk/types/mailbox_uncancel_response.py
@@ -26,7 +26,7 @@ class Data(BaseModel):
address: Optional[str] = None
- billing_mode: Literal["rent", "included"] = FieldInfo(alias="billingMode")
+ billing_mode: Literal["rent", "included", "domain"] = FieldInfo(alias="billingMode")
cancel_at_period_end: bool = FieldInfo(alias="cancelAtPeriodEnd")
@@ -38,6 +38,8 @@ class Data(BaseModel):
current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
+ domain_id: Optional[str] = FieldInfo(alias="domainId", default=None)
+
inbound_messages: DataInboundMessages = FieldInfo(alias="inboundMessages")
label: Optional[str] = None
diff --git a/src/mobilerun_sdk/types/mailbox_update_response.py b/src/mobilerun_sdk/types/mailbox_update_response.py
index 893d9928..99de186b 100644
--- a/src/mobilerun_sdk/types/mailbox_update_response.py
+++ b/src/mobilerun_sdk/types/mailbox_update_response.py
@@ -26,7 +26,7 @@ class Data(BaseModel):
address: Optional[str] = None
- billing_mode: Literal["rent", "included"] = FieldInfo(alias="billingMode")
+ billing_mode: Literal["rent", "included", "domain"] = FieldInfo(alias="billingMode")
cancel_at_period_end: bool = FieldInfo(alias="cancelAtPeriodEnd")
@@ -38,6 +38,8 @@ class Data(BaseModel):
current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
+ domain_id: Optional[str] = FieldInfo(alias="domainId", default=None)
+
inbound_messages: DataInboundMessages = FieldInfo(alias="inboundMessages")
label: Optional[str] = None
diff --git a/src/mobilerun_sdk/types/number_create_params.py b/src/mobilerun_sdk/types/number_create_params.py
index 6098fc62..353cd5fb 100644
--- a/src/mobilerun_sdk/types/number_create_params.py
+++ b/src/mobilerun_sdk/types/number_create_params.py
@@ -11,14 +11,14 @@
class NumberCreateParams(TypedDict, total=False):
- billing_preference: Annotated[Literal["included", "rent"], PropertyInfo(alias="billingPreference")]
+ billing_preference: Annotated[Literal["included", "included_only", "rent"], PropertyInfo(alias="billingPreference")]
"""
- Prefer a free package seat ('included', default) or force the paid checkout
- ('rent')
+ Use included capacity when available, require included capacity without paid
+ fallback (included_only), or start a paid checkout (rent).
"""
country: str
- """Optional ISO 3166-1 alpha-2 country code from GET /numbers/countries.
+ """Optional ISO 3166-1 alpha-2 country code from GET /numbers/phones/countries.
Cannot be combined with `purpose`.
"""
@@ -31,7 +31,7 @@ class NumberCreateParams(TypedDict, total=False):
"""
purpose: str
- """Optional Mobilerun Phone purpose slug from GET /numbers/purposes."""
+ """Optional purpose from GET /numbers/phones/purposes."""
idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")]
"""Optional request idempotency key."""
diff --git a/src/mobilerun_sdk/types/task_get_status_response.py b/src/mobilerun_sdk/types/task_get_status_response.py
index 4446b3bb..0e0f823c 100644
--- a/src/mobilerun_sdk/types/task_get_status_response.py
+++ b/src/mobilerun_sdk/types/task_get_status_response.py
@@ -33,7 +33,7 @@ class Execution(BaseModel):
class TaskGetStatusResponse(BaseModel):
- status: Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"]
+ status: Literal["prepared", "queued", "created", "running", "cancelling", "completed", "failed", "cancelled"]
"""The status of the task"""
execution: Optional[Execution] = None
@@ -48,6 +48,12 @@ class TaskGetStatusResponse(BaseModel):
output: Optional[Dict[str, object]] = None
"""Structured output if outputSchema was set"""
+ recording_device_id: Optional[str] = FieldInfo(alias="recordingDeviceId", default=None)
+ """Device ID associated with recordingId"""
+
+ recording_id: Optional[str] = FieldInfo(alias="recordingId", default=None)
+ """ID of the task's whole-task video recording, if recordingEnabled was set"""
+
steps: Optional[int] = None
"""Number of steps taken"""
diff --git a/src/mobilerun_sdk/types/task_list_params.py b/src/mobilerun_sdk/types/task_list_params.py
index 044f84ad..1b08553e 100644
--- a/src/mobilerun_sdk/types/task_list_params.py
+++ b/src/mobilerun_sdk/types/task_list_params.py
@@ -28,4 +28,9 @@ class TaskListParams(TypedDict, total=False):
query: Optional[str]
"""Search in task description."""
- status: Optional[Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"]]
+ source: Optional[Literal["api", "agent"]]
+ """Only tasks created via the API ('api') or spawned by an agent step ('agent')."""
+
+ status: Optional[
+ Literal["prepared", "queued", "created", "running", "cancelling", "completed", "failed", "cancelled"]
+ ]
diff --git a/src/mobilerun_sdk/types/task_list_response.py b/src/mobilerun_sdk/types/task_list_response.py
index 20a9744c..07a143fd 100644
--- a/src/mobilerun_sdk/types/task_list_response.py
+++ b/src/mobilerun_sdk/types/task_list_response.py
@@ -32,7 +32,7 @@ class Item(BaseModel):
owner_id: str = FieldInfo(alias="ownerId")
- status: Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"]
+ status: Literal["prepared", "queued", "created", "running", "cancelling", "completed", "failed", "cancelled"]
task: str
@@ -43,8 +43,6 @@ class Item(BaseModel):
accessibility: Optional[bool] = None
- agent_id: Optional[int] = FieldInfo(alias="agentId", default=None)
-
apps: Optional[List[str]] = None
cancel_requested_at: Optional[datetime] = FieldInfo(alias="cancelRequestedAt", default=None)
@@ -71,9 +69,6 @@ class Item(BaseModel):
max_steps: Optional[int] = FieldInfo(alias="maxSteps", default=None)
- memory_namespace: Optional[str] = FieldInfo(alias="memoryNamespace", default=None)
- """Memory namespace for cross-task personalization"""
-
message: Optional[str] = None
output: Optional[Dict[str, object]] = None
@@ -82,6 +77,20 @@ class Item(BaseModel):
reasoning: Optional[bool] = None
+ recording_device_id: Optional[str] = FieldInfo(alias="recordingDeviceId", default=None)
+
+ recording_enabled: Optional[bool] = FieldInfo(alias="recordingEnabled", default=None)
+ """Record device video for the whole task and persist a retrievable reference"""
+
+ recording_id: Optional[str] = FieldInfo(alias="recordingId", default=None)
+
+ source: Optional[Literal["api", "agent"]] = None
+ """
+ Where the task came from: 'api' for tasks created via POST /tasks, 'agent' for
+ tasks spawned by an agent step. Agent tasks are readable (status, trajectory,
+ media) but not controllable via this API.
+ """
+
stealth: Optional[bool] = None
steps: Optional[int] = None
@@ -94,6 +103,7 @@ class Item(BaseModel):
succeeded: Optional[bool] = None
temperature: Optional[float] = None
+ """Deprecated and ignored. Sampling behavior is controlled by the model provider."""
updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None)
diff --git a/src/mobilerun_sdk/types/task_retrieve_response.py b/src/mobilerun_sdk/types/task_retrieve_response.py
index 85887f56..b0e25a6b 100644
--- a/src/mobilerun_sdk/types/task_retrieve_response.py
+++ b/src/mobilerun_sdk/types/task_retrieve_response.py
@@ -31,7 +31,7 @@ class Task(BaseModel):
owner_id: str = FieldInfo(alias="ownerId")
- status: Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"]
+ status: Literal["prepared", "queued", "created", "running", "cancelling", "completed", "failed", "cancelled"]
task: str
@@ -42,8 +42,6 @@ class Task(BaseModel):
accessibility: Optional[bool] = None
- agent_id: Optional[int] = FieldInfo(alias="agentId", default=None)
-
apps: Optional[List[str]] = None
cancel_requested_at: Optional[datetime] = FieldInfo(alias="cancelRequestedAt", default=None)
@@ -70,9 +68,6 @@ class Task(BaseModel):
max_steps: Optional[int] = FieldInfo(alias="maxSteps", default=None)
- memory_namespace: Optional[str] = FieldInfo(alias="memoryNamespace", default=None)
- """Memory namespace for cross-task personalization"""
-
message: Optional[str] = None
output: Optional[Dict[str, object]] = None
@@ -81,6 +76,20 @@ class Task(BaseModel):
reasoning: Optional[bool] = None
+ recording_device_id: Optional[str] = FieldInfo(alias="recordingDeviceId", default=None)
+
+ recording_enabled: Optional[bool] = FieldInfo(alias="recordingEnabled", default=None)
+ """Record device video for the whole task and persist a retrievable reference"""
+
+ recording_id: Optional[str] = FieldInfo(alias="recordingId", default=None)
+
+ source: Optional[Literal["api", "agent"]] = None
+ """
+ Where the task came from: 'api' for tasks created via POST /tasks, 'agent' for
+ tasks spawned by an agent step. Agent tasks are readable (status, trajectory,
+ media) but not controllable via this API.
+ """
+
stealth: Optional[bool] = None
steps: Optional[int] = None
@@ -93,6 +102,7 @@ class Task(BaseModel):
succeeded: Optional[bool] = None
temperature: Optional[float] = None
+ """Deprecated and ignored. Sampling behavior is controlled by the model provider."""
updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None)
diff --git a/src/mobilerun_sdk/types/task_run_params.py b/src/mobilerun_sdk/types/task_run_params.py
index b66cf98f..e0b99bc9 100644
--- a/src/mobilerun_sdk/types/task_run_params.py
+++ b/src/mobilerun_sdk/types/task_run_params.py
@@ -19,8 +19,6 @@ class TaskRunParams(TypedDict, total=False):
accessibility: bool
- agent_id: Annotated[int, PropertyInfo(alias="agentId")]
-
apps: SequenceNotStr[str]
continue_on_failure: Annotated[bool, PropertyInfo(alias="continueOnFailure")]
@@ -31,27 +29,35 @@ class TaskRunParams(TypedDict, total=False):
"""The display ID of the device to run the task on."""
execution_timeout: Annotated[int, PropertyInfo(alias="executionTimeout")]
+ """Maximum agent execution time in seconds (1–2700)."""
files: SequenceNotStr[str]
llm_model: Annotated[str, PropertyInfo(alias="llmModel")]
- """The LLM model identifier to use for the task (e.g. 'google/gemini-3.5-flash')"""
+ """The LLM model identifier to use for the task (e.g. 'openai/gpt-5.6-luna')"""
max_steps: Annotated[int, PropertyInfo(alias="maxSteps")]
- memory_namespace: Annotated[str, PropertyInfo(alias="memoryNamespace")]
- """Memory namespace for cross-task personalization"""
-
output_schema: Annotated[Optional[Dict[str, object]], PropertyInfo(alias="outputSchema")]
reasoning: bool
+ recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")]
+ """Record device video for the whole task and persist a retrievable reference"""
+
stealth: bool
subagent_model: Annotated[str, PropertyInfo(alias="subagentModel")]
"""LLM model used by sub-agent roles: executor, app_opener, structured_output"""
+ system_prompt: Annotated[Optional[str], PropertyInfo(alias="systemPrompt")]
+ """
+ Optional custom behavioral overlay applied on top of the agent's default system
+ prompts. Never echoed back in responses or errors.
+ """
+
temperature: float
+ """Deprecated and ignored. Sampling behavior is controlled by the model provider."""
vision: bool
diff --git a/src/mobilerun_sdk/types/task_run_response.py b/src/mobilerun_sdk/types/task_run_response.py
index 5987ba3d..6b402a65 100644
--- a/src/mobilerun_sdk/types/task_run_response.py
+++ b/src/mobilerun_sdk/types/task_run_response.py
@@ -14,7 +14,7 @@ class TaskRunResponse(BaseModel):
id: str
"""The ID of the task"""
- status: Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"]
+ status: Literal["prepared", "queued", "created", "running", "cancelling", "completed", "failed", "cancelled"]
"""The status of the task (queued or created)"""
stream_url: Optional[str] = FieldInfo(alias="streamUrl", default=None)
diff --git a/src/mobilerun_sdk/types/task_run_streamed_params.py b/src/mobilerun_sdk/types/task_run_streamed_params.py
index 2522d16b..5de0656e 100644
--- a/src/mobilerun_sdk/types/task_run_streamed_params.py
+++ b/src/mobilerun_sdk/types/task_run_streamed_params.py
@@ -19,8 +19,6 @@ class TaskRunStreamedParams(TypedDict, total=False):
accessibility: bool
- agent_id: Annotated[int, PropertyInfo(alias="agentId")]
-
apps: SequenceNotStr[str]
continue_on_failure: Annotated[bool, PropertyInfo(alias="continueOnFailure")]
@@ -31,27 +29,35 @@ class TaskRunStreamedParams(TypedDict, total=False):
"""The display ID of the device to run the task on."""
execution_timeout: Annotated[int, PropertyInfo(alias="executionTimeout")]
+ """Maximum agent execution time in seconds (1–2700)."""
files: SequenceNotStr[str]
llm_model: Annotated[str, PropertyInfo(alias="llmModel")]
- """The LLM model identifier to use for the task (e.g. 'google/gemini-3.5-flash')"""
+ """The LLM model identifier to use for the task (e.g. 'openai/gpt-5.6-luna')"""
max_steps: Annotated[int, PropertyInfo(alias="maxSteps")]
- memory_namespace: Annotated[str, PropertyInfo(alias="memoryNamespace")]
- """Memory namespace for cross-task personalization"""
-
output_schema: Annotated[Optional[Dict[str, object]], PropertyInfo(alias="outputSchema")]
reasoning: bool
+ recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")]
+ """Record device video for the whole task and persist a retrievable reference"""
+
stealth: bool
subagent_model: Annotated[str, PropertyInfo(alias="subagentModel")]
"""LLM model used by sub-agent roles: executor, app_opener, structured_output"""
+ system_prompt: Annotated[Optional[str], PropertyInfo(alias="systemPrompt")]
+ """
+ Optional custom behavioral overlay applied on top of the agent's default system
+ prompts. Never echoed back in responses or errors.
+ """
+
temperature: float
+ """Deprecated and ignored. Sampling behavior is controlled by the model provider."""
vision: bool
diff --git a/src/mobilerun_sdk/types/webhook_event_types_response.py b/src/mobilerun_sdk/types/webhook_event_types_response.py
index 2d1d9e2f..9c7439d7 100644
--- a/src/mobilerun_sdk/types/webhook_event_types_response.py
+++ b/src/mobilerun_sdk/types/webhook_event_types_response.py
@@ -1,6 +1,6 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import List
+from typing import List, Optional
from typing_extensions import Literal
from pydantic import Field as FieldInfo
@@ -17,6 +17,8 @@ class DataSourceEventSurfaces(BaseModel):
webhook: bool
+ agent: Optional[bool] = None
+
class DataSourceEvent(BaseModel):
description: str
diff --git a/src/mobilerun_sdk/types/workflows/event_dry_run_response.py b/src/mobilerun_sdk/types/workflows/event_dry_run_response.py
index b04779e3..e7bb6eee 100644
--- a/src/mobilerun_sdk/types/workflows/event_dry_run_response.py
+++ b/src/mobilerun_sdk/types/workflows/event_dry_run_response.py
@@ -13,6 +13,7 @@
"DataMatchedFlow",
"DataMatchedFlowAction",
"DataMatchedFlowFlow",
+ "DataMatchedFlowFlowRecordingPolicy",
"DataMatchedFlowGates",
"DataMatchedFlowTrigger",
"DataValidation",
@@ -23,10 +24,14 @@
class DataMatchedFlowAction(BaseModel):
continue_on_error: bool = FieldInfo(alias="continueOnError")
+ flow_action_id: str = FieldInfo(alias="flowActionId")
+
method: str
name: str
+ recording_enabled: bool = FieldInfo(alias="recordingEnabled")
+
service: Literal["tasks_api", "devices_api", "agents_api", "webhooks"]
children: Optional[List[object]] = None
@@ -38,9 +43,15 @@ class DataMatchedFlowAction(BaseModel):
params: Optional[Dict[str, object]] = None
+class DataMatchedFlowFlowRecordingPolicy(BaseModel):
+ mode: Literal["off", "flow", "selected_steps"]
+
+
class DataMatchedFlowFlow(BaseModel):
id: str
+ archived_at: Optional[str] = FieldInfo(alias="archivedAt", default=None)
+
blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None)
consecutive_failures: int = FieldInfo(alias="consecutiveFailures")
@@ -58,6 +69,10 @@ class DataMatchedFlowFlow(BaseModel):
device_ids: List[str] = FieldInfo(alias="deviceIds")
enabled: bool
+ """
+ Compatibility projection of lifecycleStatus; true only when lifecycleStatus is
+ enabled.
+ """
health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled")
@@ -69,6 +84,8 @@ class DataMatchedFlowFlow(BaseModel):
last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None)
+ lifecycle_status: Literal["enabled", "disabled", "archived"] = FieldInfo(alias="lifecycleStatus")
+
name: str
notify_on_failure: bool = FieldInfo(alias="notifyOnFailure")
@@ -80,6 +97,12 @@ class DataMatchedFlowFlow(BaseModel):
owner_id: str = FieldInfo(alias="ownerId")
recording_enabled: bool = FieldInfo(alias="recordingEnabled")
+ """
+ Deprecated: use recordingPolicy.mode ("flow" = recordingEnabled=true, "off" =
+ recordingEnabled=false).
+ """
+
+ recording_policy: DataMatchedFlowFlowRecordingPolicy = FieldInfo(alias="recordingPolicy")
self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled")
diff --git a/src/mobilerun_sdk/types/workflows/execution_abort_response.py b/src/mobilerun_sdk/types/workflows/execution_abort_response.py
index 0d9468bf..8ef853a1 100644
--- a/src/mobilerun_sdk/types/workflows/execution_abort_response.py
+++ b/src/mobilerun_sdk/types/workflows/execution_abort_response.py
@@ -13,6 +13,12 @@
class Data(BaseModel):
id: str
+ device_id: Optional[str] = FieldInfo(alias="deviceId", default=None)
+ """Device this execution targets (the job's deviceId).
+
+ Null for device-less (event-only) runs.
+ """
+
error: Optional[str] = None
event_id: Optional[str] = FieldInfo(alias="eventId", default=None)
@@ -23,7 +29,14 @@ class Data(BaseModel):
flow_name: Optional[str] = FieldInfo(alias="flowName", default=None)
- kind: Literal["live", "dry_run"]
+ invocation_id: Optional[str] = FieldInfo(alias="invocationId", default=None)
+ """Client/verify invocation key this row belongs to.
+
+ Set on live custom fires (one row per device fan-out) and on verification runs;
+ null for event/schedule live rows.
+ """
+
+ kind: Literal["live", "dry_run", "verification"]
recording_device_id: Optional[str] = FieldInfo(alias="recordingDeviceId", default=None)
diff --git a/src/mobilerun_sdk/types/workflows/execution_list_params.py b/src/mobilerun_sdk/types/workflows/execution_list_params.py
index ccc40d41..83e83d88 100644
--- a/src/mobilerun_sdk/types/workflows/execution_list_params.py
+++ b/src/mobilerun_sdk/types/workflows/execution_list_params.py
@@ -15,6 +15,8 @@ class ExecutionListParams(TypedDict, total=False):
from_: Annotated[Optional[str], PropertyInfo(alias="from")]
+ invocation_id: Annotated[str, PropertyInfo(alias="invocationId")]
+
order_by: Annotated[Literal["startedAt", "finishedAt", "status"], PropertyInfo(alias="orderBy")]
order_by_direction: Annotated[Literal["asc", "desc"], PropertyInfo(alias="orderByDirection")]
diff --git a/src/mobilerun_sdk/types/workflows/execution_list_response.py b/src/mobilerun_sdk/types/workflows/execution_list_response.py
index b7c4993f..f3d62b4c 100644
--- a/src/mobilerun_sdk/types/workflows/execution_list_response.py
+++ b/src/mobilerun_sdk/types/workflows/execution_list_response.py
@@ -8,7 +8,37 @@
from ..._models import BaseModel
from ..shared.pagination import Pagination
-__all__ = ["ExecutionListResponse", "Item"]
+__all__ = ["ExecutionListResponse", "Item", "ItemRecording"]
+
+
+class ItemRecording(BaseModel):
+ id: str
+
+ attempt: int
+
+ child_index: int = FieldInfo(alias="childIndex")
+
+ flow_action_id: Optional[str] = FieldInfo(alias="flowActionId", default=None)
+
+ iteration_index: int = FieldInfo(alias="iterationIndex")
+
+ last_error: Optional[str] = FieldInfo(alias="lastError", default=None)
+
+ parent_index: int = FieldInfo(alias="parentIndex")
+
+ recording_device_id: Optional[str] = FieldInfo(alias="recordingDeviceId", default=None)
+
+ recording_id: Optional[str] = FieldInfo(alias="recordingId", default=None)
+
+ scope: Literal["flow", "step"]
+
+ started_at: Optional[str] = FieldInfo(alias="startedAt", default=None)
+
+ status: Literal["starting", "recording", "stopping", "stopped", "failed"]
+
+ step_index: int = FieldInfo(alias="stepIndex")
+
+ stopped_at: Optional[str] = FieldInfo(alias="stoppedAt", default=None)
class Item(BaseModel):
@@ -16,6 +46,12 @@ class Item(BaseModel):
created_by: Optional[str] = FieldInfo(alias="createdBy", default=None)
+ device_id: Optional[str] = FieldInfo(alias="deviceId", default=None)
+ """Device this execution targets (the job's deviceId).
+
+ Null for device-less (event-only) runs.
+ """
+
error: Optional[str] = None
event_id: Optional[str] = FieldInfo(alias="eventId", default=None)
@@ -26,7 +62,14 @@ class Item(BaseModel):
flow_name: Optional[str] = FieldInfo(alias="flowName", default=None)
- kind: Literal["live", "dry_run"]
+ invocation_id: Optional[str] = FieldInfo(alias="invocationId", default=None)
+ """Client/verify invocation key this row belongs to.
+
+ Set on live custom fires (one row per device fan-out) and on verification runs;
+ null for event/schedule live rows.
+ """
+
+ kind: Literal["live", "dry_run", "verification"]
recording_device_id: Optional[str] = FieldInfo(alias="recordingDeviceId", default=None)
@@ -37,6 +80,12 @@ class Item(BaseModel):
the recording failed to start.
"""
+ recordings: List[ItemRecording]
+ """Durable recording segments ordered by step/loop coordinate and retry attempt.
+
+ Whole-flow recordings use -1 for every coordinate.
+ """
+
started_at: Optional[str] = FieldInfo(alias="startedAt", default=None)
status: Optional[Literal["pending", "running", "success", "failed", "cancelled", "skipped", "invalid"]] = None
diff --git a/src/mobilerun_sdk/types/workflows/execution_retrieve_response.py b/src/mobilerun_sdk/types/workflows/execution_retrieve_response.py
index de6c2d19..9af89a42 100644
--- a/src/mobilerun_sdk/types/workflows/execution_retrieve_response.py
+++ b/src/mobilerun_sdk/types/workflows/execution_retrieve_response.py
@@ -7,7 +7,7 @@
from ..._models import BaseModel
-__all__ = ["ExecutionRetrieveResponse", "Data", "DataFile"]
+__all__ = ["ExecutionRetrieveResponse", "Data", "DataFile", "DataRecording"]
class DataFile(BaseModel):
@@ -20,11 +20,47 @@ class DataFile(BaseModel):
size_bytes: int = FieldInfo(alias="sizeBytes")
+class DataRecording(BaseModel):
+ id: str
+
+ attempt: int
+
+ child_index: int = FieldInfo(alias="childIndex")
+
+ flow_action_id: Optional[str] = FieldInfo(alias="flowActionId", default=None)
+
+ iteration_index: int = FieldInfo(alias="iterationIndex")
+
+ last_error: Optional[str] = FieldInfo(alias="lastError", default=None)
+
+ parent_index: int = FieldInfo(alias="parentIndex")
+
+ recording_device_id: Optional[str] = FieldInfo(alias="recordingDeviceId", default=None)
+
+ recording_id: Optional[str] = FieldInfo(alias="recordingId", default=None)
+
+ scope: Literal["flow", "step"]
+
+ started_at: Optional[str] = FieldInfo(alias="startedAt", default=None)
+
+ status: Literal["starting", "recording", "stopping", "stopped", "failed"]
+
+ step_index: int = FieldInfo(alias="stepIndex")
+
+ stopped_at: Optional[str] = FieldInfo(alias="stoppedAt", default=None)
+
+
class Data(BaseModel):
id: str
created_by: Optional[str] = FieldInfo(alias="createdBy", default=None)
+ device_id: Optional[str] = FieldInfo(alias="deviceId", default=None)
+ """Device this execution targets (the job's deviceId).
+
+ Null for device-less (event-only) runs.
+ """
+
error: Optional[str] = None
event_id: Optional[str] = FieldInfo(alias="eventId", default=None)
@@ -42,7 +78,14 @@ class Data(BaseModel):
flow_name: Optional[str] = FieldInfo(alias="flowName", default=None)
- kind: Literal["live", "dry_run"]
+ invocation_id: Optional[str] = FieldInfo(alias="invocationId", default=None)
+ """Client/verify invocation key this row belongs to.
+
+ Set on live custom fires (one row per device fan-out) and on verification runs;
+ null for event/schedule live rows.
+ """
+
+ kind: Literal["live", "dry_run", "verification"]
recording_device_id: Optional[str] = FieldInfo(alias="recordingDeviceId", default=None)
@@ -53,6 +96,12 @@ class Data(BaseModel):
the recording failed to start.
"""
+ recordings: List[DataRecording]
+ """Durable recording segments ordered by step/loop coordinate and retry attempt.
+
+ Whole-flow recordings use -1 for every coordinate.
+ """
+
started_at: Optional[str] = FieldInfo(alias="startedAt", default=None)
status: Optional[Literal["pending", "running", "success", "failed", "cancelled", "skipped", "invalid"]] = None
diff --git a/src/mobilerun_sdk/types/workflows/flow_clone_response.py b/src/mobilerun_sdk/types/workflows/flow_clone_response.py
index 14ed8d1f..e08b73dd 100644
--- a/src/mobilerun_sdk/types/workflows/flow_clone_response.py
+++ b/src/mobilerun_sdk/types/workflows/flow_clone_response.py
@@ -7,12 +7,18 @@
from ..._models import BaseModel
-__all__ = ["FlowCloneResponse", "Data"]
+__all__ = ["FlowCloneResponse", "Data", "DataRecordingPolicy"]
+
+
+class DataRecordingPolicy(BaseModel):
+ mode: Literal["off", "flow", "selected_steps"]
class Data(BaseModel):
id: str
+ archived_at: Optional[str] = FieldInfo(alias="archivedAt", default=None)
+
blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None)
consecutive_failures: int = FieldInfo(alias="consecutiveFailures")
@@ -30,6 +36,10 @@ class Data(BaseModel):
device_ids: List[str] = FieldInfo(alias="deviceIds")
enabled: bool
+ """
+ Compatibility projection of lifecycleStatus; true only when lifecycleStatus is
+ enabled.
+ """
health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled")
@@ -41,6 +51,8 @@ class Data(BaseModel):
last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None)
+ lifecycle_status: Literal["enabled", "disabled", "archived"] = FieldInfo(alias="lifecycleStatus")
+
name: str
notify_on_failure: bool = FieldInfo(alias="notifyOnFailure")
@@ -52,6 +64,12 @@ class Data(BaseModel):
owner_id: str = FieldInfo(alias="ownerId")
recording_enabled: bool = FieldInfo(alias="recordingEnabled")
+ """
+ Deprecated: use recordingPolicy.mode ("flow" = recordingEnabled=true, "off" =
+ recordingEnabled=false).
+ """
+
+ recording_policy: DataRecordingPolicy = FieldInfo(alias="recordingPolicy")
self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled")
diff --git a/src/mobilerun_sdk/types/workflows/flow_create_params.py b/src/mobilerun_sdk/types/workflows/flow_create_params.py
index cde7b202..1a292cf5 100644
--- a/src/mobilerun_sdk/types/workflows/flow_create_params.py
+++ b/src/mobilerun_sdk/types/workflows/flow_create_params.py
@@ -8,7 +8,7 @@
from ..._types import SequenceNotStr
from ..._utils import PropertyInfo
-__all__ = ["FlowCreateParams", "Action", "ActionChild", "ActionChildOverrides", "ActionOverrides"]
+__all__ = ["FlowCreateParams", "Action", "ActionChild", "ActionChildOverrides", "ActionOverrides", "RecordingPolicy"]
class FlowCreateParams(TypedDict, total=False):
@@ -37,6 +37,12 @@ class FlowCreateParams(TypedDict, total=False):
notify_webhook_id: Annotated[Optional[str], PropertyInfo(alias="notifyWebhookId")]
recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")]
+ """Deprecated compatibility field.
+
+ true maps to recordingPolicy.mode="flow"; false maps to "off".
+ """
+
+ recording_policy: Annotated[RecordingPolicy, PropertyInfo(alias="recordingPolicy")]
self_healing_enabled: Annotated[bool, PropertyInfo(alias="selfHealingEnabled")]
@@ -58,6 +64,8 @@ class ActionChild(TypedDict, total=False):
overrides: Optional[ActionChildOverrides]
+ recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")]
+
class ActionOverrides(TypedDict, total=False):
params: Dict[str, object]
@@ -75,3 +83,9 @@ class Action(TypedDict, total=False):
name_override: Annotated[str, PropertyInfo(alias="nameOverride")]
overrides: Optional[ActionOverrides]
+
+ recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")]
+
+
+class RecordingPolicy(TypedDict, total=False):
+ mode: Required[Literal["off", "flow", "selected_steps"]]
diff --git a/src/mobilerun_sdk/types/workflows/flow_create_response.py b/src/mobilerun_sdk/types/workflows/flow_create_response.py
index a840cf45..d4129117 100644
--- a/src/mobilerun_sdk/types/workflows/flow_create_response.py
+++ b/src/mobilerun_sdk/types/workflows/flow_create_response.py
@@ -7,12 +7,18 @@
from ..._models import BaseModel
-__all__ = ["FlowCreateResponse", "Data"]
+__all__ = ["FlowCreateResponse", "Data", "DataRecordingPolicy"]
+
+
+class DataRecordingPolicy(BaseModel):
+ mode: Literal["off", "flow", "selected_steps"]
class Data(BaseModel):
id: str
+ archived_at: Optional[str] = FieldInfo(alias="archivedAt", default=None)
+
blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None)
consecutive_failures: int = FieldInfo(alias="consecutiveFailures")
@@ -30,6 +36,10 @@ class Data(BaseModel):
device_ids: List[str] = FieldInfo(alias="deviceIds")
enabled: bool
+ """
+ Compatibility projection of lifecycleStatus; true only when lifecycleStatus is
+ enabled.
+ """
health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled")
@@ -41,6 +51,8 @@ class Data(BaseModel):
last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None)
+ lifecycle_status: Literal["enabled", "disabled", "archived"] = FieldInfo(alias="lifecycleStatus")
+
name: str
notify_on_failure: bool = FieldInfo(alias="notifyOnFailure")
@@ -52,6 +64,12 @@ class Data(BaseModel):
owner_id: str = FieldInfo(alias="ownerId")
recording_enabled: bool = FieldInfo(alias="recordingEnabled")
+ """
+ Deprecated: use recordingPolicy.mode ("flow" = recordingEnabled=true, "off" =
+ recordingEnabled=false).
+ """
+
+ recording_policy: DataRecordingPolicy = FieldInfo(alias="recordingPolicy")
self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled")
diff --git a/src/mobilerun_sdk/types/workflows/flow_dry_run_response.py b/src/mobilerun_sdk/types/workflows/flow_dry_run_response.py
index d9a5bf30..5592add2 100644
--- a/src/mobilerun_sdk/types/workflows/flow_dry_run_response.py
+++ b/src/mobilerun_sdk/types/workflows/flow_dry_run_response.py
@@ -13,10 +13,14 @@
class DataAction(BaseModel):
continue_on_error: bool = FieldInfo(alias="continueOnError")
+ flow_action_id: str = FieldInfo(alias="flowActionId")
+
method: str
name: str
+ recording_enabled: bool = FieldInfo(alias="recordingEnabled")
+
service: Literal["tasks_api", "devices_api", "agents_api", "webhooks"]
children: Optional[List[object]] = None
diff --git a/src/mobilerun_sdk/types/workflows/flow_list_response.py b/src/mobilerun_sdk/types/workflows/flow_list_response.py
index 5cd546ab..01705f9f 100644
--- a/src/mobilerun_sdk/types/workflows/flow_list_response.py
+++ b/src/mobilerun_sdk/types/workflows/flow_list_response.py
@@ -8,12 +8,18 @@
from ..._models import BaseModel
from ..shared.pagination import Pagination
-__all__ = ["FlowListResponse", "Item"]
+__all__ = ["FlowListResponse", "Item", "ItemRecordingPolicy"]
+
+
+class ItemRecordingPolicy(BaseModel):
+ mode: Literal["off", "flow", "selected_steps"]
class Item(BaseModel):
id: str
+ archived_at: Optional[str] = FieldInfo(alias="archivedAt", default=None)
+
blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None)
consecutive_failures: int = FieldInfo(alias="consecutiveFailures")
@@ -31,6 +37,10 @@ class Item(BaseModel):
device_ids: List[str] = FieldInfo(alias="deviceIds")
enabled: bool
+ """
+ Compatibility projection of lifecycleStatus; true only when lifecycleStatus is
+ enabled.
+ """
health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled")
@@ -42,6 +52,8 @@ class Item(BaseModel):
last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None)
+ lifecycle_status: Literal["enabled", "disabled", "archived"] = FieldInfo(alias="lifecycleStatus")
+
name: str
notify_on_failure: bool = FieldInfo(alias="notifyOnFailure")
@@ -53,6 +65,12 @@ class Item(BaseModel):
owner_id: str = FieldInfo(alias="ownerId")
recording_enabled: bool = FieldInfo(alias="recordingEnabled")
+ """
+ Deprecated: use recordingPolicy.mode ("flow" = recordingEnabled=true, "off" =
+ recordingEnabled=false).
+ """
+
+ recording_policy: ItemRecordingPolicy = FieldInfo(alias="recordingPolicy")
self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled")
diff --git a/src/mobilerun_sdk/types/workflows/flow_retrieve_response.py b/src/mobilerun_sdk/types/workflows/flow_retrieve_response.py
index dab4caa9..b4cd5806 100644
--- a/src/mobilerun_sdk/types/workflows/flow_retrieve_response.py
+++ b/src/mobilerun_sdk/types/workflows/flow_retrieve_response.py
@@ -7,12 +7,18 @@
from ..._models import BaseModel
-__all__ = ["FlowRetrieveResponse", "Data"]
+__all__ = ["FlowRetrieveResponse", "Data", "DataRecordingPolicy"]
+
+
+class DataRecordingPolicy(BaseModel):
+ mode: Literal["off", "flow", "selected_steps"]
class Data(BaseModel):
id: str
+ archived_at: Optional[str] = FieldInfo(alias="archivedAt", default=None)
+
blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None)
consecutive_failures: int = FieldInfo(alias="consecutiveFailures")
@@ -30,6 +36,10 @@ class Data(BaseModel):
device_ids: List[str] = FieldInfo(alias="deviceIds")
enabled: bool
+ """
+ Compatibility projection of lifecycleStatus; true only when lifecycleStatus is
+ enabled.
+ """
health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled")
@@ -41,6 +51,8 @@ class Data(BaseModel):
last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None)
+ lifecycle_status: Literal["enabled", "disabled", "archived"] = FieldInfo(alias="lifecycleStatus")
+
name: str
notify_on_failure: bool = FieldInfo(alias="notifyOnFailure")
@@ -52,6 +64,12 @@ class Data(BaseModel):
owner_id: str = FieldInfo(alias="ownerId")
recording_enabled: bool = FieldInfo(alias="recordingEnabled")
+ """
+ Deprecated: use recordingPolicy.mode ("flow" = recordingEnabled=true, "off" =
+ recordingEnabled=false).
+ """
+
+ recording_policy: DataRecordingPolicy = FieldInfo(alias="recordingPolicy")
self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled")
diff --git a/src/mobilerun_sdk/types/workflows/flow_unblock_response.py b/src/mobilerun_sdk/types/workflows/flow_unblock_response.py
index 0429bba4..d71392de 100644
--- a/src/mobilerun_sdk/types/workflows/flow_unblock_response.py
+++ b/src/mobilerun_sdk/types/workflows/flow_unblock_response.py
@@ -7,12 +7,18 @@
from ..._models import BaseModel
-__all__ = ["FlowUnblockResponse", "Data"]
+__all__ = ["FlowUnblockResponse", "Data", "DataRecordingPolicy"]
+
+
+class DataRecordingPolicy(BaseModel):
+ mode: Literal["off", "flow", "selected_steps"]
class Data(BaseModel):
id: str
+ archived_at: Optional[str] = FieldInfo(alias="archivedAt", default=None)
+
blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None)
consecutive_failures: int = FieldInfo(alias="consecutiveFailures")
@@ -30,6 +36,10 @@ class Data(BaseModel):
device_ids: List[str] = FieldInfo(alias="deviceIds")
enabled: bool
+ """
+ Compatibility projection of lifecycleStatus; true only when lifecycleStatus is
+ enabled.
+ """
health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled")
@@ -41,6 +51,8 @@ class Data(BaseModel):
last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None)
+ lifecycle_status: Literal["enabled", "disabled", "archived"] = FieldInfo(alias="lifecycleStatus")
+
name: str
notify_on_failure: bool = FieldInfo(alias="notifyOnFailure")
@@ -52,6 +64,12 @@ class Data(BaseModel):
owner_id: str = FieldInfo(alias="ownerId")
recording_enabled: bool = FieldInfo(alias="recordingEnabled")
+ """
+ Deprecated: use recordingPolicy.mode ("flow" = recordingEnabled=true, "off" =
+ recordingEnabled=false).
+ """
+
+ recording_policy: DataRecordingPolicy = FieldInfo(alias="recordingPolicy")
self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled")
diff --git a/src/mobilerun_sdk/types/workflows/flow_update_params.py b/src/mobilerun_sdk/types/workflows/flow_update_params.py
index 8db31b2e..9f32e4bb 100644
--- a/src/mobilerun_sdk/types/workflows/flow_update_params.py
+++ b/src/mobilerun_sdk/types/workflows/flow_update_params.py
@@ -3,12 +3,12 @@
from __future__ import annotations
from typing import Optional
-from typing_extensions import Literal, Annotated, TypedDict
+from typing_extensions import Literal, Required, Annotated, TypedDict
from ..._types import SequenceNotStr
from ..._utils import PropertyInfo
-__all__ = ["FlowUpdateParams"]
+__all__ = ["FlowUpdateParams", "RecordingPolicy"]
class FlowUpdateParams(TypedDict, total=False):
@@ -24,6 +24,9 @@ class FlowUpdateParams(TypedDict, total=False):
health_monitoring_enabled: Annotated[bool, PropertyInfo(alias="healthMonitoringEnabled")]
+ lifecycle_status: Annotated[Literal["enabled", "disabled"], PropertyInfo(alias="lifecycleStatus")]
+ """Set the visible agent lifecycle. Archive remains available only through DELETE."""
+
name: str
notify_on_failure: Annotated[bool, PropertyInfo(alias="notifyOnFailure")]
@@ -33,9 +36,19 @@ class FlowUpdateParams(TypedDict, total=False):
notify_webhook_id: Annotated[Optional[str], PropertyInfo(alias="notifyWebhookId")]
recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")]
+ """Deprecated compatibility field.
+
+ true maps to recordingPolicy.mode="flow"; false maps to "off".
+ """
+
+ recording_policy: Annotated[RecordingPolicy, PropertyInfo(alias="recordingPolicy")]
self_healing_enabled: Annotated[bool, PropertyInfo(alias="selfHealingEnabled")]
self_healing_max_attempts: Annotated[int, PropertyInfo(alias="selfHealingMaxAttempts")]
trigger_id: Annotated[str, PropertyInfo(alias="triggerId")]
+
+
+class RecordingPolicy(TypedDict, total=False):
+ mode: Required[Literal["off", "flow", "selected_steps"]]
diff --git a/src/mobilerun_sdk/types/workflows/flow_update_response.py b/src/mobilerun_sdk/types/workflows/flow_update_response.py
index ad10348f..511e934a 100644
--- a/src/mobilerun_sdk/types/workflows/flow_update_response.py
+++ b/src/mobilerun_sdk/types/workflows/flow_update_response.py
@@ -7,12 +7,18 @@
from ..._models import BaseModel
-__all__ = ["FlowUpdateResponse", "Data"]
+__all__ = ["FlowUpdateResponse", "Data", "DataRecordingPolicy"]
+
+
+class DataRecordingPolicy(BaseModel):
+ mode: Literal["off", "flow", "selected_steps"]
class Data(BaseModel):
id: str
+ archived_at: Optional[str] = FieldInfo(alias="archivedAt", default=None)
+
blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None)
consecutive_failures: int = FieldInfo(alias="consecutiveFailures")
@@ -30,6 +36,10 @@ class Data(BaseModel):
device_ids: List[str] = FieldInfo(alias="deviceIds")
enabled: bool
+ """
+ Compatibility projection of lifecycleStatus; true only when lifecycleStatus is
+ enabled.
+ """
health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled")
@@ -41,6 +51,8 @@ class Data(BaseModel):
last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None)
+ lifecycle_status: Literal["enabled", "disabled", "archived"] = FieldInfo(alias="lifecycleStatus")
+
name: str
notify_on_failure: bool = FieldInfo(alias="notifyOnFailure")
@@ -52,6 +64,12 @@ class Data(BaseModel):
owner_id: str = FieldInfo(alias="ownerId")
recording_enabled: bool = FieldInfo(alias="recordingEnabled")
+ """
+ Deprecated: use recordingPolicy.mode ("flow" = recordingEnabled=true, "off" =
+ recordingEnabled=false).
+ """
+
+ recording_policy: DataRecordingPolicy = FieldInfo(alias="recordingPolicy")
self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled")
diff --git a/src/mobilerun_sdk/types/workflows/flows/action_add_params.py b/src/mobilerun_sdk/types/workflows/flows/action_add_params.py
index 1275209c..88af2ccf 100644
--- a/src/mobilerun_sdk/types/workflows/flows/action_add_params.py
+++ b/src/mobilerun_sdk/types/workflows/flows/action_add_params.py
@@ -25,6 +25,8 @@ class ActionAddParams(TypedDict, total=False):
parent_flow_action_id: Annotated[Optional[str], PropertyInfo(alias="parentFlowActionId")]
+ recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")]
+
class ChildOverrides(TypedDict, total=False):
params: Dict[str, object]
@@ -41,6 +43,8 @@ class Child(TypedDict, total=False):
overrides: Optional[ChildOverrides]
+ recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")]
+
class Overrides(TypedDict, total=False):
params: Dict[str, object]
diff --git a/src/mobilerun_sdk/types/workflows/flows/action_add_response.py b/src/mobilerun_sdk/types/workflows/flows/action_add_response.py
index 00d02c81..420a30e5 100644
--- a/src/mobilerun_sdk/types/workflows/flows/action_add_response.py
+++ b/src/mobilerun_sdk/types/workflows/flows/action_add_response.py
@@ -32,6 +32,12 @@ class Data(BaseModel):
position: int
+ recording_enabled: bool = FieldInfo(alias="recordingEnabled")
+ """
+ Selected for per-step recording under the flow's "selected_steps" recording
+ policy.
+ """
+
class ActionAddResponse(BaseModel):
data: Data
diff --git a/src/mobilerun_sdk/types/workflows/flows/action_list_response.py b/src/mobilerun_sdk/types/workflows/flows/action_list_response.py
index 88c4965b..1ff8dd43 100644
--- a/src/mobilerun_sdk/types/workflows/flows/action_list_response.py
+++ b/src/mobilerun_sdk/types/workflows/flows/action_list_response.py
@@ -32,6 +32,12 @@ class Data(BaseModel):
position: int
+ recording_enabled: bool = FieldInfo(alias="recordingEnabled")
+ """
+ Selected for per-step recording under the flow's "selected_steps" recording
+ policy.
+ """
+
class ActionListResponse(BaseModel):
data: List[Data]
diff --git a/src/mobilerun_sdk/types/workflows/flows/action_replace_params.py b/src/mobilerun_sdk/types/workflows/flows/action_replace_params.py
index ec5c42a1..fd89af25 100644
--- a/src/mobilerun_sdk/types/workflows/flows/action_replace_params.py
+++ b/src/mobilerun_sdk/types/workflows/flows/action_replace_params.py
@@ -29,6 +29,8 @@ class ActionChild(TypedDict, total=False):
overrides: Optional[ActionChildOverrides]
+ recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")]
+
class ActionOverrides(TypedDict, total=False):
params: Dict[str, object]
@@ -46,3 +48,5 @@ class Action(TypedDict, total=False):
name_override: Annotated[str, PropertyInfo(alias="nameOverride")]
overrides: Optional[ActionOverrides]
+
+ recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")]
diff --git a/src/mobilerun_sdk/types/workflows/flows/action_replace_response.py b/src/mobilerun_sdk/types/workflows/flows/action_replace_response.py
index cf358f90..a9939a84 100644
--- a/src/mobilerun_sdk/types/workflows/flows/action_replace_response.py
+++ b/src/mobilerun_sdk/types/workflows/flows/action_replace_response.py
@@ -32,6 +32,12 @@ class Data(BaseModel):
position: int
+ recording_enabled: bool = FieldInfo(alias="recordingEnabled")
+ """
+ Selected for per-step recording under the flow's "selected_steps" recording
+ policy.
+ """
+
class ActionReplaceResponse(BaseModel):
data: List[Data]
diff --git a/src/mobilerun_sdk/types/workflows/trigger_fire_params.py b/src/mobilerun_sdk/types/workflows/trigger_fire_params.py
index 03847b71..1a1f266d 100644
--- a/src/mobilerun_sdk/types/workflows/trigger_fire_params.py
+++ b/src/mobilerun_sdk/types/workflows/trigger_fire_params.py
@@ -3,7 +3,9 @@
from __future__ import annotations
from typing import Dict
-from typing_extensions import Required, TypedDict
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
__all__ = ["TriggerFireParams"]
@@ -15,3 +17,11 @@ class TriggerFireParams(TypedDict, total=False):
Validated against the trigger's customPayloadSchema when one is configured;
otherwise only "must be a JSON object" is enforced.
"""
+
+ invocation_id: Annotated[str, PropertyInfo(alias="invocationId")]
+ """Optional client-supplied idempotency key.
+
+ When provided, a flow that already has an execution for this (flow,
+ invocationId) is skipped and `deduplicated` is true. When omitted a fresh
+ server-side id is generated (no dedup).
+ """
diff --git a/src/mobilerun_sdk/types/workflows/trigger_fire_response.py b/src/mobilerun_sdk/types/workflows/trigger_fire_response.py
index b0b49511..324a5242 100644
--- a/src/mobilerun_sdk/types/workflows/trigger_fire_response.py
+++ b/src/mobilerun_sdk/types/workflows/trigger_fire_response.py
@@ -8,15 +8,23 @@
class TriggerFireResponse(BaseModel):
+ deduplicated: bool
+ """
+ True when at least one attached flow was skipped because it already had an
+ execution for this (flow, invocationId). Only ever true when the client supplied
+ invocationId.
+ """
+
enqueued_count: int = FieldInfo(alias="enqueuedCount")
"""Number of flow executions enqueued.
- May be 0 if no flows are attached to this trigger, or if all attached flows are
- currently in cooldown.
+ May be 0 if no flows are attached to this trigger, if all attached flows are
+ currently in cooldown, or if every attached flow was deduplicated.
"""
invocation_id: str = FieldInfo(alias="invocationId")
- """Unique ID for this fire invocation.
-
- Job IDs in the execution queue are derived from it (one per enqueued flow).
+ """
+ Unique ID for this fire invocation (echoes the client-supplied invocationId, or
+ a generated one). Job IDs in the execution queue are derived from it (one per
+ enqueued flow).
"""
diff --git a/tests/api_resources/assistant/test_conversations.py b/tests/api_resources/assistant/test_conversations.py
index 32ef5823..4652e4ad 100644
--- a/tests/api_resources/assistant/test_conversations.py
+++ b/tests/api_resources/assistant/test_conversations.py
@@ -172,6 +172,15 @@ def test_method_abort(self, client: Mobilerun) -> None:
)
assert_matches_type(ConversationAbortResponse, conversation, path=["response"])
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_abort_with_all_params(self, client: Mobilerun) -> None:
+ conversation = client.assistant.conversations.abort(
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ expected_turn_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(ConversationAbortResponse, conversation, path=["response"])
+
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_raw_response_abort(self, client: Mobilerun) -> None:
@@ -580,6 +589,15 @@ async def test_method_abort(self, async_client: AsyncMobilerun) -> None:
)
assert_matches_type(ConversationAbortResponse, conversation, path=["response"])
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_abort_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ conversation = await async_client.assistant.conversations.abort(
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ expected_turn_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(ConversationAbortResponse, conversation, path=["response"])
+
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
async def test_raw_response_abort(self, async_client: AsyncMobilerun) -> None:
diff --git a/tests/api_resources/connect/test_proxies.py b/tests/api_resources/connect/test_proxies.py
index acd84195..f2e62efb 100644
--- a/tests/api_resources/connect/test_proxies.py
+++ b/tests/api_resources/connect/test_proxies.py
@@ -113,6 +113,16 @@ def test_method_buy(self, client: Mobilerun) -> None:
)
assert_matches_type(ProxyBuyResponse, proxy, path=["response"])
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_buy_with_all_params(self, client: Mobilerun) -> None:
+ proxy = client.connect.proxies.buy(
+ country="country",
+ type="dedicated_residential",
+ idempotency_key="Idempotency-Key",
+ )
+ assert_matches_type(ProxyBuyResponse, proxy, path=["response"])
+
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_raw_response_buy(self, client: Mobilerun) -> None:
@@ -395,6 +405,16 @@ async def test_method_buy(self, async_client: AsyncMobilerun) -> None:
)
assert_matches_type(ProxyBuyResponse, proxy, path=["response"])
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_buy_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ proxy = await async_client.connect.proxies.buy(
+ country="country",
+ type="dedicated_residential",
+ idempotency_key="Idempotency-Key",
+ )
+ assert_matches_type(ProxyBuyResponse, proxy, path=["response"])
+
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
async def test_raw_response_buy(self, async_client: AsyncMobilerun) -> None:
diff --git a/tests/api_resources/devices/test_apps.py b/tests/api_resources/devices/test_apps.py
index c1281d68..aa3726ed 100644
--- a/tests/api_resources/devices/test_apps.py
+++ b/tests/api_resources/devices/test_apps.py
@@ -219,7 +219,9 @@ def test_method_install_with_all_params_overload_1(self, client: Mobilerun) -> N
device_id="deviceId",
bundle_id="x",
background=True,
+ country="se",
package_name="x",
+ version_code=1,
x_device_display_id=0,
)
assert app is None
@@ -278,6 +280,8 @@ def test_method_install_with_all_params_overload_2(self, client: Mobilerun) -> N
package_name="x",
background=True,
bundle_id="x",
+ country="se",
+ version_code=1,
x_device_display_id=0,
)
assert app is None
@@ -769,7 +773,9 @@ async def test_method_install_with_all_params_overload_1(self, async_client: Asy
device_id="deviceId",
bundle_id="x",
background=True,
+ country="se",
package_name="x",
+ version_code=1,
x_device_display_id=0,
)
assert app is None
@@ -828,6 +834,8 @@ async def test_method_install_with_all_params_overload_2(self, async_client: Asy
package_name="x",
background=True,
bundle_id="x",
+ country="se",
+ version_code=1,
x_device_display_id=0,
)
assert app is None
diff --git a/tests/api_resources/devices/test_keyboard.py b/tests/api_resources/devices/test_keyboard.py
index 766a63b8..29044ca3 100644
--- a/tests/api_resources/devices/test_keyboard.py
+++ b/tests/api_resources/devices/test_keyboard.py
@@ -138,6 +138,7 @@ def test_method_write_with_all_params(self, client: Mobilerun) -> None:
device_id="deviceId",
text="text",
clear=True,
+ completion_mode="accepted",
error_rate=0,
stealth=True,
wpm=0,
@@ -311,6 +312,7 @@ async def test_method_write_with_all_params(self, async_client: AsyncMobilerun)
device_id="deviceId",
text="text",
clear=True,
+ completion_mode="accepted",
error_rate=0,
stealth=True,
wpm=0,
diff --git a/tests/api_resources/devices/test_recordings.py b/tests/api_resources/devices/test_recordings.py
index f3e134fb..4d72e541 100644
--- a/tests/api_resources/devices/test_recordings.py
+++ b/tests/api_resources/devices/test_recordings.py
@@ -140,6 +140,7 @@ def test_method_start_with_all_params(self, client: Mobilerun) -> None:
recording = client.devices.recordings.start(
device_id="deviceId",
name="name",
+ quality=1,
retention_days=1,
types=["string"],
)
@@ -511,6 +512,7 @@ async def test_method_start_with_all_params(self, async_client: AsyncMobilerun)
recording = await async_client.devices.recordings.start(
device_id="deviceId",
name="name",
+ quality=1,
retention_days=1,
types=["string"],
)
diff --git a/tests/api_resources/esims/__init__.py b/tests/api_resources/esims/__init__.py
deleted file mode 100644
index fd8019a9..00000000
--- a/tests/api_resources/esims/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/esims/test_messages.py b/tests/api_resources/esims/test_messages.py
deleted file mode 100644
index aa71f91d..00000000
--- a/tests/api_resources/esims/test_messages.py
+++ /dev/null
@@ -1,262 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-import os
-from typing import Any, cast
-
-import pytest
-
-from tests.utils import assert_matches_type
-from mobilerun_sdk import Mobilerun, AsyncMobilerun
-from mobilerun_sdk.types.esims import MessageListResponse, MessageSendResponse
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestMessages:
- parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_list(self, client: Mobilerun) -> None:
- message = client.esims.messages.list(
- id="550e8400-e29b-41d4-a716-446655440000",
- )
- assert_matches_type(MessageListResponse, message, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_list_with_all_params(self, client: Mobilerun) -> None:
- message = client.esims.messages.list(
- id="550e8400-e29b-41d4-a716-446655440000",
- direction="all",
- number_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- page=1,
- page_size=1,
- peer_key="x",
- peer_number="xxx",
- status="all",
- )
- assert_matches_type(MessageListResponse, message, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_list(self, client: Mobilerun) -> None:
- response = client.esims.messages.with_raw_response.list(
- id="550e8400-e29b-41d4-a716-446655440000",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- message = response.parse()
- assert_matches_type(MessageListResponse, message, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_list(self, client: Mobilerun) -> None:
- with client.esims.messages.with_streaming_response.list(
- id="550e8400-e29b-41d4-a716-446655440000",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- message = response.parse()
- assert_matches_type(MessageListResponse, message, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_path_params_list(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- client.esims.messages.with_raw_response.list(
- id="",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_send(self, client: Mobilerun) -> None:
- message = client.esims.messages.send(
- id="550e8400-e29b-41d4-a716-446655440000",
- body="x",
- to="+15551230001",
- )
- assert_matches_type(MessageSendResponse, message, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_send_with_all_params(self, client: Mobilerun) -> None:
- message = client.esims.messages.send(
- id="550e8400-e29b-41d4-a716-446655440000",
- body="x",
- to="+15551230001",
- client_request_id="x",
- delivery_report=True,
- )
- assert_matches_type(MessageSendResponse, message, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_send(self, client: Mobilerun) -> None:
- response = client.esims.messages.with_raw_response.send(
- id="550e8400-e29b-41d4-a716-446655440000",
- body="x",
- to="+15551230001",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- message = response.parse()
- assert_matches_type(MessageSendResponse, message, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_send(self, client: Mobilerun) -> None:
- with client.esims.messages.with_streaming_response.send(
- id="550e8400-e29b-41d4-a716-446655440000",
- body="x",
- to="+15551230001",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- message = response.parse()
- assert_matches_type(MessageSendResponse, message, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_path_params_send(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- client.esims.messages.with_raw_response.send(
- id="",
- body="x",
- to="+15551230001",
- )
-
-
-class TestAsyncMessages:
- parametrize = pytest.mark.parametrize(
- "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_list(self, async_client: AsyncMobilerun) -> None:
- message = await async_client.esims.messages.list(
- id="550e8400-e29b-41d4-a716-446655440000",
- )
- assert_matches_type(MessageListResponse, message, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None:
- message = await async_client.esims.messages.list(
- id="550e8400-e29b-41d4-a716-446655440000",
- direction="all",
- number_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- page=1,
- page_size=1,
- peer_key="x",
- peer_number="xxx",
- status="all",
- )
- assert_matches_type(MessageListResponse, message, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.esims.messages.with_raw_response.list(
- id="550e8400-e29b-41d4-a716-446655440000",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- message = await response.parse()
- assert_matches_type(MessageListResponse, message, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None:
- async with async_client.esims.messages.with_streaming_response.list(
- id="550e8400-e29b-41d4-a716-446655440000",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- message = await response.parse()
- assert_matches_type(MessageListResponse, message, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_path_params_list(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- await async_client.esims.messages.with_raw_response.list(
- id="",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_send(self, async_client: AsyncMobilerun) -> None:
- message = await async_client.esims.messages.send(
- id="550e8400-e29b-41d4-a716-446655440000",
- body="x",
- to="+15551230001",
- )
- assert_matches_type(MessageSendResponse, message, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_send_with_all_params(self, async_client: AsyncMobilerun) -> None:
- message = await async_client.esims.messages.send(
- id="550e8400-e29b-41d4-a716-446655440000",
- body="x",
- to="+15551230001",
- client_request_id="x",
- delivery_report=True,
- )
- assert_matches_type(MessageSendResponse, message, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_send(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.esims.messages.with_raw_response.send(
- id="550e8400-e29b-41d4-a716-446655440000",
- body="x",
- to="+15551230001",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- message = await response.parse()
- assert_matches_type(MessageSendResponse, message, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_send(self, async_client: AsyncMobilerun) -> None:
- async with async_client.esims.messages.with_streaming_response.send(
- id="550e8400-e29b-41d4-a716-446655440000",
- body="x",
- to="+15551230001",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- message = await response.parse()
- assert_matches_type(MessageSendResponse, message, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_path_params_send(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- await async_client.esims.messages.with_raw_response.send(
- id="",
- body="x",
- to="+15551230001",
- )
diff --git a/tests/api_resources/test_esims.py b/tests/api_resources/test_esims.py
deleted file mode 100644
index a47275d3..00000000
--- a/tests/api_resources/test_esims.py
+++ /dev/null
@@ -1,953 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-import os
-from typing import Any, cast
-
-import pytest
-
-from tests.utils import assert_matches_type
-from mobilerun_sdk import Mobilerun, AsyncMobilerun
-from mobilerun_sdk.types import (
- EsimListResponse,
- EsimCreateResponse,
- EsimImportResponse,
- EsimUpdateResponse,
- EsimInstallResponse,
- EsimCapacityResponse,
- EsimRetrieveResponse,
- EsimSelectorResponse,
- EsimInstallStatusResponse,
- EsimConfirmPaymentResponse,
-)
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestEsims:
- parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_create(self, client: Mobilerun) -> None:
- esim = client.esims.create()
- assert_matches_type(EsimCreateResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_create_with_all_params(self, client: Mobilerun) -> None:
- esim = client.esims.create(
- idempotency_key="idempotencyKey",
- name="Mom's phone",
- )
- assert_matches_type(EsimCreateResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_create(self, client: Mobilerun) -> None:
- response = client.esims.with_raw_response.create()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = response.parse()
- assert_matches_type(EsimCreateResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_create(self, client: Mobilerun) -> None:
- with client.esims.with_streaming_response.create() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = response.parse()
- assert_matches_type(EsimCreateResponse, esim, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_retrieve(self, client: Mobilerun) -> None:
- esim = client.esims.retrieve(
- "550e8400-e29b-41d4-a716-446655440000",
- )
- assert_matches_type(EsimRetrieveResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_retrieve(self, client: Mobilerun) -> None:
- response = client.esims.with_raw_response.retrieve(
- "550e8400-e29b-41d4-a716-446655440000",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = response.parse()
- assert_matches_type(EsimRetrieveResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_retrieve(self, client: Mobilerun) -> None:
- with client.esims.with_streaming_response.retrieve(
- "550e8400-e29b-41d4-a716-446655440000",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = response.parse()
- assert_matches_type(EsimRetrieveResponse, esim, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_path_params_retrieve(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- client.esims.with_raw_response.retrieve(
- "",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_update(self, client: Mobilerun) -> None:
- esim = client.esims.update(
- id="550e8400-e29b-41d4-a716-446655440000",
- )
- assert_matches_type(EsimUpdateResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_update_with_all_params(self, client: Mobilerun) -> None:
- esim = client.esims.update(
- id="550e8400-e29b-41d4-a716-446655440000",
- msisdn="+33612345678",
- name="Mom's phone",
- )
- assert_matches_type(EsimUpdateResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_update(self, client: Mobilerun) -> None:
- response = client.esims.with_raw_response.update(
- id="550e8400-e29b-41d4-a716-446655440000",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = response.parse()
- assert_matches_type(EsimUpdateResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_update(self, client: Mobilerun) -> None:
- with client.esims.with_streaming_response.update(
- id="550e8400-e29b-41d4-a716-446655440000",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = response.parse()
- assert_matches_type(EsimUpdateResponse, esim, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_path_params_update(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- client.esims.with_raw_response.update(
- id="",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_list(self, client: Mobilerun) -> None:
- esim = client.esims.list()
- assert_matches_type(EsimListResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_list_with_all_params(self, client: Mobilerun) -> None:
- esim = client.esims.list(
- mine="true",
- page=1,
- page_size=1,
- status="all",
- )
- assert_matches_type(EsimListResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_list(self, client: Mobilerun) -> None:
- response = client.esims.with_raw_response.list()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = response.parse()
- assert_matches_type(EsimListResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_list(self, client: Mobilerun) -> None:
- with client.esims.with_streaming_response.list() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = response.parse()
- assert_matches_type(EsimListResponse, esim, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_delete(self, client: Mobilerun) -> None:
- esim = client.esims.delete(
- "550e8400-e29b-41d4-a716-446655440000",
- )
- assert esim is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_delete(self, client: Mobilerun) -> None:
- response = client.esims.with_raw_response.delete(
- "550e8400-e29b-41d4-a716-446655440000",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = response.parse()
- assert esim is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_delete(self, client: Mobilerun) -> None:
- with client.esims.with_streaming_response.delete(
- "550e8400-e29b-41d4-a716-446655440000",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = response.parse()
- assert esim is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_path_params_delete(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- client.esims.with_raw_response.delete(
- "",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_capacity(self, client: Mobilerun) -> None:
- esim = client.esims.capacity()
- assert_matches_type(EsimCapacityResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_capacity(self, client: Mobilerun) -> None:
- response = client.esims.with_raw_response.capacity()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = response.parse()
- assert_matches_type(EsimCapacityResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_capacity(self, client: Mobilerun) -> None:
- with client.esims.with_streaming_response.capacity() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = response.parse()
- assert_matches_type(EsimCapacityResponse, esim, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_confirm_payment(self, client: Mobilerun) -> None:
- esim = client.esims.confirm_payment(
- "550e8400-e29b-41d4-a716-446655440000",
- )
- assert_matches_type(EsimConfirmPaymentResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_confirm_payment(self, client: Mobilerun) -> None:
- response = client.esims.with_raw_response.confirm_payment(
- "550e8400-e29b-41d4-a716-446655440000",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = response.parse()
- assert_matches_type(EsimConfirmPaymentResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_confirm_payment(self, client: Mobilerun) -> None:
- with client.esims.with_streaming_response.confirm_payment(
- "550e8400-e29b-41d4-a716-446655440000",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = response.parse()
- assert_matches_type(EsimConfirmPaymentResponse, esim, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_path_params_confirm_payment(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- client.esims.with_raw_response.confirm_payment(
- "",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_import(self, client: Mobilerun) -> None:
- esim = client.esims.import_()
- assert_matches_type(EsimImportResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_import_with_all_params(self, client: Mobilerun) -> None:
- esim = client.esims.import_(
- auto_install=True,
- carrier_name="carrierName",
- confirmation_code="confirmationCode",
- country_code="countryCode",
- device_id="physedge-dev-8f3a2c",
- idempotency_key="x",
- lpa_code="LPA:1$smdp.example.com$QR-MATCH-1",
- matching_id="matchingId",
- msisdn="+33612345678",
- name="Mom's phone",
- notes="notes",
- smdp_address="smdp.example.com",
- )
- assert_matches_type(EsimImportResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_import(self, client: Mobilerun) -> None:
- response = client.esims.with_raw_response.import_()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = response.parse()
- assert_matches_type(EsimImportResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_import(self, client: Mobilerun) -> None:
- with client.esims.with_streaming_response.import_() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = response.parse()
- assert_matches_type(EsimImportResponse, esim, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_install(self, client: Mobilerun) -> None:
- esim = client.esims.install(
- id="550e8400-e29b-41d4-a716-446655440000",
- )
- assert_matches_type(EsimInstallResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_install_with_all_params(self, client: Mobilerun) -> None:
- esim = client.esims.install(
- id="550e8400-e29b-41d4-a716-446655440000",
- device_id="physedge-dev-8f3a2c",
- )
- assert_matches_type(EsimInstallResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_install(self, client: Mobilerun) -> None:
- response = client.esims.with_raw_response.install(
- id="550e8400-e29b-41d4-a716-446655440000",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = response.parse()
- assert_matches_type(EsimInstallResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_install(self, client: Mobilerun) -> None:
- with client.esims.with_streaming_response.install(
- id="550e8400-e29b-41d4-a716-446655440000",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = response.parse()
- assert_matches_type(EsimInstallResponse, esim, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_path_params_install(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- client.esims.with_raw_response.install(
- id="",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_install_status(self, client: Mobilerun) -> None:
- esim = client.esims.install_status(
- "550e8400-e29b-41d4-a716-446655440000",
- )
- assert_matches_type(EsimInstallStatusResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_install_status(self, client: Mobilerun) -> None:
- response = client.esims.with_raw_response.install_status(
- "550e8400-e29b-41d4-a716-446655440000",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = response.parse()
- assert_matches_type(EsimInstallStatusResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_install_status(self, client: Mobilerun) -> None:
- with client.esims.with_streaming_response.install_status(
- "550e8400-e29b-41d4-a716-446655440000",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = response.parse()
- assert_matches_type(EsimInstallStatusResponse, esim, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_path_params_install_status(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- client.esims.with_raw_response.install_status(
- "",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_selector(self, client: Mobilerun) -> None:
- esim = client.esims.selector()
- assert_matches_type(EsimSelectorResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_selector_with_all_params(self, client: Mobilerun) -> None:
- esim = client.esims.selector(
- page=1,
- page_size=1,
- )
- assert_matches_type(EsimSelectorResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_selector(self, client: Mobilerun) -> None:
- response = client.esims.with_raw_response.selector()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = response.parse()
- assert_matches_type(EsimSelectorResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_selector(self, client: Mobilerun) -> None:
- with client.esims.with_streaming_response.selector() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = response.parse()
- assert_matches_type(EsimSelectorResponse, esim, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
-
-class TestAsyncEsims:
- parametrize = pytest.mark.parametrize(
- "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_create(self, async_client: AsyncMobilerun) -> None:
- esim = await async_client.esims.create()
- assert_matches_type(EsimCreateResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_create_with_all_params(self, async_client: AsyncMobilerun) -> None:
- esim = await async_client.esims.create(
- idempotency_key="idempotencyKey",
- name="Mom's phone",
- )
- assert_matches_type(EsimCreateResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_create(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.esims.with_raw_response.create()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = await response.parse()
- assert_matches_type(EsimCreateResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_create(self, async_client: AsyncMobilerun) -> None:
- async with async_client.esims.with_streaming_response.create() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = await response.parse()
- assert_matches_type(EsimCreateResponse, esim, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_retrieve(self, async_client: AsyncMobilerun) -> None:
- esim = await async_client.esims.retrieve(
- "550e8400-e29b-41d4-a716-446655440000",
- )
- assert_matches_type(EsimRetrieveResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_retrieve(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.esims.with_raw_response.retrieve(
- "550e8400-e29b-41d4-a716-446655440000",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = await response.parse()
- assert_matches_type(EsimRetrieveResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_retrieve(self, async_client: AsyncMobilerun) -> None:
- async with async_client.esims.with_streaming_response.retrieve(
- "550e8400-e29b-41d4-a716-446655440000",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = await response.parse()
- assert_matches_type(EsimRetrieveResponse, esim, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_path_params_retrieve(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- await async_client.esims.with_raw_response.retrieve(
- "",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_update(self, async_client: AsyncMobilerun) -> None:
- esim = await async_client.esims.update(
- id="550e8400-e29b-41d4-a716-446655440000",
- )
- assert_matches_type(EsimUpdateResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_update_with_all_params(self, async_client: AsyncMobilerun) -> None:
- esim = await async_client.esims.update(
- id="550e8400-e29b-41d4-a716-446655440000",
- msisdn="+33612345678",
- name="Mom's phone",
- )
- assert_matches_type(EsimUpdateResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_update(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.esims.with_raw_response.update(
- id="550e8400-e29b-41d4-a716-446655440000",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = await response.parse()
- assert_matches_type(EsimUpdateResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_update(self, async_client: AsyncMobilerun) -> None:
- async with async_client.esims.with_streaming_response.update(
- id="550e8400-e29b-41d4-a716-446655440000",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = await response.parse()
- assert_matches_type(EsimUpdateResponse, esim, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_path_params_update(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- await async_client.esims.with_raw_response.update(
- id="",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_list(self, async_client: AsyncMobilerun) -> None:
- esim = await async_client.esims.list()
- assert_matches_type(EsimListResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None:
- esim = await async_client.esims.list(
- mine="true",
- page=1,
- page_size=1,
- status="all",
- )
- assert_matches_type(EsimListResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.esims.with_raw_response.list()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = await response.parse()
- assert_matches_type(EsimListResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None:
- async with async_client.esims.with_streaming_response.list() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = await response.parse()
- assert_matches_type(EsimListResponse, esim, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_delete(self, async_client: AsyncMobilerun) -> None:
- esim = await async_client.esims.delete(
- "550e8400-e29b-41d4-a716-446655440000",
- )
- assert esim is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_delete(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.esims.with_raw_response.delete(
- "550e8400-e29b-41d4-a716-446655440000",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = await response.parse()
- assert esim is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_delete(self, async_client: AsyncMobilerun) -> None:
- async with async_client.esims.with_streaming_response.delete(
- "550e8400-e29b-41d4-a716-446655440000",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = await response.parse()
- assert esim is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_path_params_delete(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- await async_client.esims.with_raw_response.delete(
- "",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_capacity(self, async_client: AsyncMobilerun) -> None:
- esim = await async_client.esims.capacity()
- assert_matches_type(EsimCapacityResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_capacity(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.esims.with_raw_response.capacity()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = await response.parse()
- assert_matches_type(EsimCapacityResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_capacity(self, async_client: AsyncMobilerun) -> None:
- async with async_client.esims.with_streaming_response.capacity() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = await response.parse()
- assert_matches_type(EsimCapacityResponse, esim, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_confirm_payment(self, async_client: AsyncMobilerun) -> None:
- esim = await async_client.esims.confirm_payment(
- "550e8400-e29b-41d4-a716-446655440000",
- )
- assert_matches_type(EsimConfirmPaymentResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_confirm_payment(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.esims.with_raw_response.confirm_payment(
- "550e8400-e29b-41d4-a716-446655440000",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = await response.parse()
- assert_matches_type(EsimConfirmPaymentResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_confirm_payment(self, async_client: AsyncMobilerun) -> None:
- async with async_client.esims.with_streaming_response.confirm_payment(
- "550e8400-e29b-41d4-a716-446655440000",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = await response.parse()
- assert_matches_type(EsimConfirmPaymentResponse, esim, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_path_params_confirm_payment(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- await async_client.esims.with_raw_response.confirm_payment(
- "",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_import(self, async_client: AsyncMobilerun) -> None:
- esim = await async_client.esims.import_()
- assert_matches_type(EsimImportResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_import_with_all_params(self, async_client: AsyncMobilerun) -> None:
- esim = await async_client.esims.import_(
- auto_install=True,
- carrier_name="carrierName",
- confirmation_code="confirmationCode",
- country_code="countryCode",
- device_id="physedge-dev-8f3a2c",
- idempotency_key="x",
- lpa_code="LPA:1$smdp.example.com$QR-MATCH-1",
- matching_id="matchingId",
- msisdn="+33612345678",
- name="Mom's phone",
- notes="notes",
- smdp_address="smdp.example.com",
- )
- assert_matches_type(EsimImportResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_import(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.esims.with_raw_response.import_()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = await response.parse()
- assert_matches_type(EsimImportResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_import(self, async_client: AsyncMobilerun) -> None:
- async with async_client.esims.with_streaming_response.import_() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = await response.parse()
- assert_matches_type(EsimImportResponse, esim, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_install(self, async_client: AsyncMobilerun) -> None:
- esim = await async_client.esims.install(
- id="550e8400-e29b-41d4-a716-446655440000",
- )
- assert_matches_type(EsimInstallResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_install_with_all_params(self, async_client: AsyncMobilerun) -> None:
- esim = await async_client.esims.install(
- id="550e8400-e29b-41d4-a716-446655440000",
- device_id="physedge-dev-8f3a2c",
- )
- assert_matches_type(EsimInstallResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_install(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.esims.with_raw_response.install(
- id="550e8400-e29b-41d4-a716-446655440000",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = await response.parse()
- assert_matches_type(EsimInstallResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_install(self, async_client: AsyncMobilerun) -> None:
- async with async_client.esims.with_streaming_response.install(
- id="550e8400-e29b-41d4-a716-446655440000",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = await response.parse()
- assert_matches_type(EsimInstallResponse, esim, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_path_params_install(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- await async_client.esims.with_raw_response.install(
- id="",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_install_status(self, async_client: AsyncMobilerun) -> None:
- esim = await async_client.esims.install_status(
- "550e8400-e29b-41d4-a716-446655440000",
- )
- assert_matches_type(EsimInstallStatusResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_install_status(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.esims.with_raw_response.install_status(
- "550e8400-e29b-41d4-a716-446655440000",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = await response.parse()
- assert_matches_type(EsimInstallStatusResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_install_status(self, async_client: AsyncMobilerun) -> None:
- async with async_client.esims.with_streaming_response.install_status(
- "550e8400-e29b-41d4-a716-446655440000",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = await response.parse()
- assert_matches_type(EsimInstallStatusResponse, esim, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_path_params_install_status(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- await async_client.esims.with_raw_response.install_status(
- "",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_selector(self, async_client: AsyncMobilerun) -> None:
- esim = await async_client.esims.selector()
- assert_matches_type(EsimSelectorResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_selector_with_all_params(self, async_client: AsyncMobilerun) -> None:
- esim = await async_client.esims.selector(
- page=1,
- page_size=1,
- )
- assert_matches_type(EsimSelectorResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_selector(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.esims.with_raw_response.selector()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- esim = await response.parse()
- assert_matches_type(EsimSelectorResponse, esim, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_selector(self, async_client: AsyncMobilerun) -> None:
- async with async_client.esims.with_streaming_response.selector() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- esim = await response.parse()
- assert_matches_type(EsimSelectorResponse, esim, path=["response"])
-
- assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_mailboxes.py b/tests/api_resources/test_mailboxes.py
index fee64e12..45d04734 100644
--- a/tests/api_resources/test_mailboxes.py
+++ b/tests/api_resources/test_mailboxes.py
@@ -42,6 +42,7 @@ def test_method_create_with_all_params(self, client: Mobilerun) -> None:
mailbox = client.mailboxes.create(
client_request_id="x",
billing_preference="included",
+ domain_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
label="label",
local_part="jane-doe",
)
@@ -435,6 +436,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncMobilerun)
mailbox = await async_client.mailboxes.create(
client_request_id="x",
billing_preference="included",
+ domain_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
label="label",
local_part="jane-doe",
)
diff --git a/tests/api_resources/test_tasks.py b/tests/api_resources/test_tasks.py
index cf65f53d..8ff81d06 100644
--- a/tests/api_resources/test_tasks.py
+++ b/tests/api_resources/test_tasks.py
@@ -84,7 +84,8 @@ def test_method_list_with_all_params(self, client: Mobilerun) -> None:
page=1,
page_size=1,
query="query",
- status="queued",
+ source="api",
+ status="prepared",
)
assert_matches_type(TaskListResponse, task, path=["response"])
@@ -252,7 +253,6 @@ def test_method_run_with_all_params(self, client: Mobilerun) -> None:
device_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
task="x",
accessibility=True,
- agent_id=0,
apps=["string"],
continue_on_failure=True,
credentials=[
@@ -262,15 +262,16 @@ def test_method_run_with_all_params(self, client: Mobilerun) -> None:
}
],
display_id=0,
- execution_timeout=0,
+ execution_timeout=1,
files=["string"],
llm_model="llmModel",
max_steps=0,
- memory_namespace="memoryNamespace",
output_schema={"foo": "bar"},
reasoning=True,
+ recording_enabled=True,
stealth=True,
subagent_model="subagentModel",
+ system_prompt="systemPrompt",
temperature=0,
vision=True,
vpn_country="US",
@@ -322,7 +323,6 @@ def test_method_run_streamed_with_all_params(self, client: Mobilerun) -> None:
device_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
task="x",
accessibility=True,
- agent_id=0,
apps=["string"],
continue_on_failure=True,
credentials=[
@@ -332,15 +332,16 @@ def test_method_run_streamed_with_all_params(self, client: Mobilerun) -> None:
}
],
display_id=0,
- execution_timeout=0,
+ execution_timeout=1,
files=["string"],
llm_model="llmModel",
max_steps=0,
- memory_namespace="memoryNamespace",
output_schema={"foo": "bar"},
reasoning=True,
+ recording_enabled=True,
stealth=True,
subagent_model="subagentModel",
+ system_prompt="systemPrompt",
temperature=0,
vision=True,
vpn_country="US",
@@ -528,7 +529,8 @@ async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -
page=1,
page_size=1,
query="query",
- status="queued",
+ source="api",
+ status="prepared",
)
assert_matches_type(TaskListResponse, task, path=["response"])
@@ -696,7 +698,6 @@ async def test_method_run_with_all_params(self, async_client: AsyncMobilerun) ->
device_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
task="x",
accessibility=True,
- agent_id=0,
apps=["string"],
continue_on_failure=True,
credentials=[
@@ -706,15 +707,16 @@ async def test_method_run_with_all_params(self, async_client: AsyncMobilerun) ->
}
],
display_id=0,
- execution_timeout=0,
+ execution_timeout=1,
files=["string"],
llm_model="llmModel",
max_steps=0,
- memory_namespace="memoryNamespace",
output_schema={"foo": "bar"},
reasoning=True,
+ recording_enabled=True,
stealth=True,
subagent_model="subagentModel",
+ system_prompt="systemPrompt",
temperature=0,
vision=True,
vpn_country="US",
@@ -766,7 +768,6 @@ async def test_method_run_streamed_with_all_params(self, async_client: AsyncMobi
device_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
task="x",
accessibility=True,
- agent_id=0,
apps=["string"],
continue_on_failure=True,
credentials=[
@@ -776,15 +777,16 @@ async def test_method_run_streamed_with_all_params(self, async_client: AsyncMobi
}
],
display_id=0,
- execution_timeout=0,
+ execution_timeout=1,
files=["string"],
llm_model="llmModel",
max_steps=0,
- memory_namespace="memoryNamespace",
output_schema={"foo": "bar"},
reasoning=True,
+ recording_enabled=True,
stealth=True,
subagent_model="subagentModel",
+ system_prompt="systemPrompt",
temperature=0,
vision=True,
vpn_country="US",
diff --git a/tests/api_resources/workflows/flows/test_actions.py b/tests/api_resources/workflows/flows/test_actions.py
index 797f7246..21f7ca88 100644
--- a/tests/api_resources/workflows/flows/test_actions.py
+++ b/tests/api_resources/workflows/flows/test_actions.py
@@ -88,12 +88,14 @@ def test_method_add_with_all_params(self, client: Mobilerun) -> None:
"continue_on_error": True,
"name_override": "x",
"overrides": {"params": {"foo": "bar"}},
+ "recording_enabled": True,
}
],
continue_on_error=True,
name_override="x",
overrides={"params": {"foo": "bar"}},
parent_flow_action_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ recording_enabled=True,
)
assert_matches_type(ActionAddResponse, action, path=["response"])
@@ -327,12 +329,14 @@ async def test_method_add_with_all_params(self, async_client: AsyncMobilerun) ->
"continue_on_error": True,
"name_override": "x",
"overrides": {"params": {"foo": "bar"}},
+ "recording_enabled": True,
}
],
continue_on_error=True,
name_override="x",
overrides={"params": {"foo": "bar"}},
parent_flow_action_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ recording_enabled=True,
)
assert_matches_type(ActionAddResponse, action, path=["response"])
diff --git a/tests/api_resources/workflows/test_executions.py b/tests/api_resources/workflows/test_executions.py
index 7b24f4c0..20711476 100644
--- a/tests/api_resources/workflows/test_executions.py
+++ b/tests/api_resources/workflows/test_executions.py
@@ -76,6 +76,7 @@ def test_method_list_with_all_params(self, client: Mobilerun) -> None:
execution = client.workflows.executions.list(
flow_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
from_="from",
+ invocation_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
order_by="startedAt",
order_by_direction="asc",
page=1,
@@ -250,6 +251,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -
execution = await async_client.workflows.executions.list(
flow_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
from_="from",
+ invocation_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
order_by="startedAt",
order_by_direction="asc",
page=1,
diff --git a/tests/api_resources/workflows/test_flows.py b/tests/api_resources/workflows/test_flows.py
index 845d0f4f..1b4987c7 100644
--- a/tests/api_resources/workflows/test_flows.py
+++ b/tests/api_resources/workflows/test_flows.py
@@ -57,11 +57,13 @@ def test_method_create_with_all_params(self, client: Mobilerun) -> None:
"continue_on_error": True,
"name_override": "x",
"overrides": {"params": {"foo": "bar"}},
+ "recording_enabled": True,
}
],
"continue_on_error": True,
"name_override": "x",
"overrides": {"params": {"foo": "bar"}},
+ "recording_enabled": True,
}
],
name="x",
@@ -76,6 +78,7 @@ def test_method_create_with_all_params(self, client: Mobilerun) -> None:
notify_on_success=True,
notify_webhook_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
recording_enabled=True,
+ recording_policy={"mode": "off"},
self_healing_enabled=True,
self_healing_max_attempts=1,
)
@@ -182,11 +185,13 @@ def test_method_update_with_all_params(self, client: Mobilerun) -> None:
device_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],
enabled=True,
health_monitoring_enabled=True,
+ lifecycle_status="enabled",
name="x",
notify_on_failure=True,
notify_on_success=True,
notify_webhook_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
recording_enabled=True,
+ recording_policy={"mode": "off"},
self_healing_enabled=True,
self_healing_max_attempts=1,
trigger_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
@@ -537,11 +542,13 @@ async def test_method_create_with_all_params(self, async_client: AsyncMobilerun)
"continue_on_error": True,
"name_override": "x",
"overrides": {"params": {"foo": "bar"}},
+ "recording_enabled": True,
}
],
"continue_on_error": True,
"name_override": "x",
"overrides": {"params": {"foo": "bar"}},
+ "recording_enabled": True,
}
],
name="x",
@@ -556,6 +563,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncMobilerun)
notify_on_success=True,
notify_webhook_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
recording_enabled=True,
+ recording_policy={"mode": "off"},
self_healing_enabled=True,
self_healing_max_attempts=1,
)
@@ -662,11 +670,13 @@ async def test_method_update_with_all_params(self, async_client: AsyncMobilerun)
device_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],
enabled=True,
health_monitoring_enabled=True,
+ lifecycle_status="enabled",
name="x",
notify_on_failure=True,
notify_on_success=True,
notify_webhook_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
recording_enabled=True,
+ recording_policy={"mode": "off"},
self_healing_enabled=True,
self_healing_max_attempts=1,
trigger_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
diff --git a/tests/api_resources/workflows/test_triggers.py b/tests/api_resources/workflows/test_triggers.py
index c29dff8d..7149612e 100644
--- a/tests/api_resources/workflows/test_triggers.py
+++ b/tests/api_resources/workflows/test_triggers.py
@@ -293,6 +293,16 @@ def test_method_fire(self, client: Mobilerun) -> None:
)
assert_matches_type(TriggerFireResponse, trigger, path=["response"])
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_fire_with_all_params(self, client: Mobilerun) -> None:
+ trigger = client.workflows.triggers.fire(
+ trigger_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ payload={"foo": "bar"},
+ invocation_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(TriggerFireResponse, trigger, path=["response"])
+
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_raw_response_fire(self, client: Mobilerun) -> None:
@@ -605,6 +615,16 @@ async def test_method_fire(self, async_client: AsyncMobilerun) -> None:
)
assert_matches_type(TriggerFireResponse, trigger, path=["response"])
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_fire_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ trigger = await async_client.workflows.triggers.fire(
+ trigger_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ payload={"foo": "bar"},
+ invocation_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(TriggerFireResponse, trigger, path=["response"])
+
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
async def test_raw_response_fire(self, async_client: AsyncMobilerun) -> None: