diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 7325798..fbd9082 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "1.4.1"
+ ".": "1.5.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index 56f5a81..49508b3 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 17
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cas-parser%2Fcas-parser-56b0f699c5437d9e5326626d35dfc972c17d01f12cb416c7f4854c8ea6d0e95e.yml
-openapi_spec_hash: 158f405c1880706266d83e6ff16b9d2f
-config_hash: 41c337f5cda03b13880617490f82bad0
+configured_endpoints: 21
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cas-parser%2Fcas-parser-d9763d006969b49a1473851069fdfa429eb13133b64103a62963bb70ddb22305.yml
+openapi_spec_hash: 6aee689b7a759b12c85c088c15e29bc0
+config_hash: 4ab3e1ee76a463e0ed214541260ee12e
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 61d9a73..1fe0243 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,16 @@
# Changelog
+## 1.5.0 (2026-02-23)
+
+Full Changelog: [v1.4.1...v1.5.0](https://github.com/CASParser/cas-parser-python/compare/v1.4.1...v1.5.0)
+
+### Features
+
+* **api:** api update ([8a5eeaa](https://github.com/CASParser/cas-parser-python/commit/8a5eeaa3334343c0a5e8268d06c0c25d7dfdef00))
+* **api:** api update ([478ce0c](https://github.com/CASParser/cas-parser-python/commit/478ce0c2535de083e5c6f9248d0df77e6bafb410))
+* **api:** api update ([dcf866c](https://github.com/CASParser/cas-parser-python/commit/dcf866c9577a219abb273e5b34e2c95bda3404f2))
+* **api:** manual updates ([a4d6336](https://github.com/CASParser/cas-parser-python/commit/a4d6336829387e982ac938935252129ff5131f65))
+
## 1.4.1 (2026-02-20)
Full Changelog: [v1.4.0...v1.4.1](https://github.com/CASParser/cas-parser-python/compare/v1.4.0...v1.4.1)
diff --git a/api.md b/api.md
index d92590b..164b61d 100644
--- a/api.md
+++ b/api.md
@@ -8,7 +8,7 @@ from cas_parser.types import CreditCheckResponse
Methods:
-- client.credits.check() -> CreditCheckResponse
+- client.credits.check() -> CreditCheckResponse
# Logs
@@ -20,8 +20,8 @@ from cas_parser.types import LogCreateResponse, LogGetSummaryResponse
Methods:
-- client.logs.create(\*\*params) -> LogCreateResponse
-- client.logs.get_summary(\*\*params) -> LogGetSummaryResponse
+- client.logs.create(\*\*params) -> LogCreateResponse
+- client.logs.get_summary(\*\*params) -> LogGetSummaryResponse
# AccessToken
@@ -33,7 +33,7 @@ from cas_parser.types import AccessTokenCreateResponse
Methods:
-- client.access_token.create(\*\*params) -> AccessTokenCreateResponse
+- client.access_token.create(\*\*params) -> AccessTokenCreateResponse
# VerifyToken
@@ -45,7 +45,7 @@ from cas_parser.types import VerifyTokenVerifyResponse
Methods:
-- client.verify_token.verify() -> VerifyTokenVerifyResponse
+- client.verify_token.verify() -> VerifyTokenVerifyResponse
# CamsKfintech
@@ -133,3 +133,23 @@ Methods:
Methods:
- client.smart.parse_cas_pdf(\*\*params) -> UnifiedResponse
+
+# InboundEmail
+
+Types:
+
+```python
+from cas_parser.types import (
+ InboundEmailCreateResponse,
+ InboundEmailRetrieveResponse,
+ InboundEmailListResponse,
+ InboundEmailDeleteResponse,
+)
+```
+
+Methods:
+
+- client.inbound_email.create(\*\*params) -> InboundEmailCreateResponse
+- client.inbound_email.retrieve(inbound_email_id) -> InboundEmailRetrieveResponse
+- client.inbound_email.list(\*\*params) -> InboundEmailListResponse
+- client.inbound_email.delete(inbound_email_id) -> InboundEmailDeleteResponse
diff --git a/pyproject.toml b/pyproject.toml
index e9c0aea..4e79dc8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "cas-parser-python"
-version = "1.4.1"
+version = "1.5.0"
description = "The official Python library for the cas-parser API"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/src/cas_parser/_client.py b/src/cas_parser/_client.py
index 02dc18a..e63f97f 100644
--- a/src/cas_parser/_client.py
+++ b/src/cas_parser/_client.py
@@ -43,6 +43,7 @@
verify_token,
cams_kfintech,
contract_note,
+ inbound_email,
)
from .resources.logs import LogsResource, AsyncLogsResource
from .resources.nsdl import NsdlResource, AsyncNsdlResource
@@ -55,6 +56,7 @@
from .resources.verify_token import VerifyTokenResource, AsyncVerifyTokenResource
from .resources.cams_kfintech import CamsKfintechResource, AsyncCamsKfintechResource
from .resources.contract_note import ContractNoteResource, AsyncContractNoteResource
+ from .resources.inbound_email import InboundEmailResource, AsyncInboundEmailResource
__all__ = [
"ENVIRONMENTS",
@@ -220,6 +222,12 @@ def smart(self) -> SmartResource:
return SmartResource(self)
+ @cached_property
+ def inbound_email(self) -> InboundEmailResource:
+ from .resources.inbound_email import InboundEmailResource
+
+ return InboundEmailResource(self)
+
@cached_property
def with_raw_response(self) -> CasParserWithRawResponse:
return CasParserWithRawResponse(self)
@@ -480,6 +488,12 @@ def smart(self) -> AsyncSmartResource:
return AsyncSmartResource(self)
+ @cached_property
+ def inbound_email(self) -> AsyncInboundEmailResource:
+ from .resources.inbound_email import AsyncInboundEmailResource
+
+ return AsyncInboundEmailResource(self)
+
@cached_property
def with_raw_response(self) -> AsyncCasParserWithRawResponse:
return AsyncCasParserWithRawResponse(self)
@@ -667,6 +681,12 @@ def smart(self) -> smart.SmartResourceWithRawResponse:
return SmartResourceWithRawResponse(self._client.smart)
+ @cached_property
+ def inbound_email(self) -> inbound_email.InboundEmailResourceWithRawResponse:
+ from .resources.inbound_email import InboundEmailResourceWithRawResponse
+
+ return InboundEmailResourceWithRawResponse(self._client.inbound_email)
+
class AsyncCasParserWithRawResponse:
_client: AsyncCasParser
@@ -740,6 +760,12 @@ def smart(self) -> smart.AsyncSmartResourceWithRawResponse:
return AsyncSmartResourceWithRawResponse(self._client.smart)
+ @cached_property
+ def inbound_email(self) -> inbound_email.AsyncInboundEmailResourceWithRawResponse:
+ from .resources.inbound_email import AsyncInboundEmailResourceWithRawResponse
+
+ return AsyncInboundEmailResourceWithRawResponse(self._client.inbound_email)
+
class CasParserWithStreamedResponse:
_client: CasParser
@@ -813,6 +839,12 @@ def smart(self) -> smart.SmartResourceWithStreamingResponse:
return SmartResourceWithStreamingResponse(self._client.smart)
+ @cached_property
+ def inbound_email(self) -> inbound_email.InboundEmailResourceWithStreamingResponse:
+ from .resources.inbound_email import InboundEmailResourceWithStreamingResponse
+
+ return InboundEmailResourceWithStreamingResponse(self._client.inbound_email)
+
class AsyncCasParserWithStreamedResponse:
_client: AsyncCasParser
@@ -886,6 +918,12 @@ def smart(self) -> smart.AsyncSmartResourceWithStreamingResponse:
return AsyncSmartResourceWithStreamingResponse(self._client.smart)
+ @cached_property
+ def inbound_email(self) -> inbound_email.AsyncInboundEmailResourceWithStreamingResponse:
+ from .resources.inbound_email import AsyncInboundEmailResourceWithStreamingResponse
+
+ return AsyncInboundEmailResourceWithStreamingResponse(self._client.inbound_email)
+
Client = CasParser
diff --git a/src/cas_parser/_version.py b/src/cas_parser/_version.py
index eaa6152..e73e451 100644
--- a/src/cas_parser/_version.py
+++ b/src/cas_parser/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "cas_parser"
-__version__ = "1.4.1" # x-release-please-version
+__version__ = "1.5.0" # x-release-please-version
diff --git a/src/cas_parser/resources/__init__.py b/src/cas_parser/resources/__init__.py
index ac91596..34f05f7 100644
--- a/src/cas_parser/resources/__init__.py
+++ b/src/cas_parser/resources/__init__.py
@@ -88,6 +88,14 @@
ContractNoteResourceWithStreamingResponse,
AsyncContractNoteResourceWithStreamingResponse,
)
+from .inbound_email import (
+ InboundEmailResource,
+ AsyncInboundEmailResource,
+ InboundEmailResourceWithRawResponse,
+ AsyncInboundEmailResourceWithRawResponse,
+ InboundEmailResourceWithStreamingResponse,
+ AsyncInboundEmailResourceWithStreamingResponse,
+)
__all__ = [
"CreditsResource",
@@ -156,4 +164,10 @@
"AsyncSmartResourceWithRawResponse",
"SmartResourceWithStreamingResponse",
"AsyncSmartResourceWithStreamingResponse",
+ "InboundEmailResource",
+ "AsyncInboundEmailResource",
+ "InboundEmailResourceWithRawResponse",
+ "AsyncInboundEmailResourceWithRawResponse",
+ "InboundEmailResourceWithStreamingResponse",
+ "AsyncInboundEmailResourceWithStreamingResponse",
]
diff --git a/src/cas_parser/resources/access_token.py b/src/cas_parser/resources/access_token.py
index aa92680..bfda93b 100644
--- a/src/cas_parser/resources/access_token.py
+++ b/src/cas_parser/resources/access_token.py
@@ -58,6 +58,8 @@ def create(
**Use this endpoint from your backend** to create tokens that can be safely
passed to frontend/SDK.
+ **Legacy path:** `/v1/access-token` (still supported)
+
Access tokens:
- Are prefixed with `at_` for easy identification
@@ -77,7 +79,7 @@ def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
return self._post(
- "/v1/access-token",
+ "/v1/token",
body=maybe_transform(
{"expiry_minutes": expiry_minutes}, access_token_create_params.AccessTokenCreateParams
),
@@ -125,6 +127,8 @@ async def create(
**Use this endpoint from your backend** to create tokens that can be safely
passed to frontend/SDK.
+ **Legacy path:** `/v1/access-token` (still supported)
+
Access tokens:
- Are prefixed with `at_` for easy identification
@@ -144,7 +148,7 @@ async def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
return await self._post(
- "/v1/access-token",
+ "/v1/token",
body=await async_maybe_transform(
{"expiry_minutes": expiry_minutes}, access_token_create_params.AccessTokenCreateParams
),
diff --git a/src/cas_parser/resources/credits.py b/src/cas_parser/resources/credits.py
index 4a86474..264693d 100644
--- a/src/cas_parser/resources/credits.py
+++ b/src/cas_parser/resources/credits.py
@@ -61,7 +61,7 @@ def check(
Credits reset at the start of each billing period.
"""
return self._post(
- "/credits",
+ "/v1/credits",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -111,7 +111,7 @@ async def check(
Credits reset at the start of each billing period.
"""
return await self._post(
- "/credits",
+ "/v1/credits",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
diff --git a/src/cas_parser/resources/inbound_email.py b/src/cas_parser/resources/inbound_email.py
new file mode 100644
index 0000000..e20ae7b
--- /dev/null
+++ b/src/cas_parser/resources/inbound_email.py
@@ -0,0 +1,563 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, List
+from typing_extensions import Literal
+
+import httpx
+
+from ..types import inbound_email_list_params, inbound_email_create_params
+from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from .._utils import 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 .._base_client import make_request_options
+from ..types.inbound_email_list_response import InboundEmailListResponse
+from ..types.inbound_email_create_response import InboundEmailCreateResponse
+from ..types.inbound_email_delete_response import InboundEmailDeleteResponse
+from ..types.inbound_email_retrieve_response import InboundEmailRetrieveResponse
+
+__all__ = ["InboundEmailResource", "AsyncInboundEmailResource"]
+
+
+class InboundEmailResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> InboundEmailResourceWithRawResponse:
+ """
+ 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/CASParser/cas-parser-python#accessing-raw-response-data-eg-headers
+ """
+ return InboundEmailResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> InboundEmailResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/CASParser/cas-parser-python#with_streaming_response
+ """
+ return InboundEmailResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ callback_url: str,
+ alias: str | Omit = omit,
+ allowed_sources: List[Literal["cdsl", "nsdl", "cams", "kfintech"]] | Omit = omit,
+ metadata: Dict[str, str] | Omit = omit,
+ reference: 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,
+ ) -> InboundEmailCreateResponse:
+ """
+ Create a dedicated inbound email address for collecting CAS statements via email
+ forwarding.
+
+ **How it works:**
+
+ 1. Create an inbound email with your webhook URL
+ 2. Display the email address to your user (e.g., "Forward your CAS to
+ ie_xxx@import.casparser.in")
+ 3. When an investor forwards a CAS email, we verify the sender and deliver to
+ your webhook
+
+ **Webhook Delivery:**
+
+ - We POST to your `callback_url` with JSON body containing files (matching
+ EmailCASFile schema)
+ - Failed deliveries are retried automatically with exponential backoff
+
+ **Inactivity:**
+
+ - Inbound emails with no activity in 30 days are marked inactive
+ - Active inbound emails remain operational indefinitely
+
+ Args:
+ callback_url: Webhook URL where we POST email notifications. Must be HTTPS in production (HTTP
+ allowed for localhost during development).
+
+ alias: Optional custom email prefix for user-friendly addresses.
+
+ - Must be 3-32 characters
+ - Alphanumeric + hyphens only
+ - Must start and end with letter/number
+ - Example: `john-portfolio@import.casparser.in`
+ - If omitted, generates random ID like `ie_abc123xyz@import.casparser.in`
+
+ allowed_sources: Filter emails by CAS provider. If omitted, accepts all providers.
+
+ - `cdsl` → eCAS@cdslstatement.com
+ - `nsdl` → NSDL-CAS@nsdl.co.in
+ - `cams` → donotreply@camsonline.com
+ - `kfintech` → samfS@kfintech.com
+
+ metadata: Optional key-value pairs (max 10) to include in webhook payload. Useful for
+ passing context like plan_type, campaign_id, etc.
+
+ reference: Your internal identifier (e.g., user_id, account_id). Returned in webhook
+ payload for correlation.
+
+ 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(
+ "/v4/inbound-email",
+ body=maybe_transform(
+ {
+ "callback_url": callback_url,
+ "alias": alias,
+ "allowed_sources": allowed_sources,
+ "metadata": metadata,
+ "reference": reference,
+ },
+ inbound_email_create_params.InboundEmailCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=InboundEmailCreateResponse,
+ )
+
+ def retrieve(
+ self,
+ inbound_email_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,
+ ) -> InboundEmailRetrieveResponse:
+ """
+ Retrieve details of a specific mailbox including statistics.
+
+ 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 inbound_email_id:
+ raise ValueError(f"Expected a non-empty value for `inbound_email_id` but received {inbound_email_id!r}")
+ return self._get(
+ f"/v4/inbound-email/{inbound_email_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=InboundEmailRetrieveResponse,
+ )
+
+ def list(
+ self,
+ *,
+ limit: int | Omit = omit,
+ offset: int | Omit = omit,
+ status: Literal["active", "paused", "all"] | 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,
+ ) -> InboundEmailListResponse:
+ """List all mailboxes associated with your API key.
+
+ Returns active and inactive
+ mailboxes (deleted mailboxes are excluded).
+
+ Args:
+ limit: Maximum number of inbound emails to return
+
+ offset: Pagination offset
+
+ status: Filter by status
+
+ 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(
+ "/v4/inbound-email",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "offset": offset,
+ "status": status,
+ },
+ inbound_email_list_params.InboundEmailListParams,
+ ),
+ ),
+ cast_to=InboundEmailListResponse,
+ )
+
+ def delete(
+ self,
+ inbound_email_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,
+ ) -> InboundEmailDeleteResponse:
+ """Permanently delete an inbound email address.
+
+ It will stop accepting emails.
+
+ **Note:** Deletion is immediate and cannot be undone. Any emails received after
+ deletion will be rejected.
+
+ 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 inbound_email_id:
+ raise ValueError(f"Expected a non-empty value for `inbound_email_id` but received {inbound_email_id!r}")
+ return self._delete(
+ f"/v4/inbound-email/{inbound_email_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=InboundEmailDeleteResponse,
+ )
+
+
+class AsyncInboundEmailResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncInboundEmailResourceWithRawResponse:
+ """
+ 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/CASParser/cas-parser-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncInboundEmailResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncInboundEmailResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/CASParser/cas-parser-python#with_streaming_response
+ """
+ return AsyncInboundEmailResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ callback_url: str,
+ alias: str | Omit = omit,
+ allowed_sources: List[Literal["cdsl", "nsdl", "cams", "kfintech"]] | Omit = omit,
+ metadata: Dict[str, str] | Omit = omit,
+ reference: 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,
+ ) -> InboundEmailCreateResponse:
+ """
+ Create a dedicated inbound email address for collecting CAS statements via email
+ forwarding.
+
+ **How it works:**
+
+ 1. Create an inbound email with your webhook URL
+ 2. Display the email address to your user (e.g., "Forward your CAS to
+ ie_xxx@import.casparser.in")
+ 3. When an investor forwards a CAS email, we verify the sender and deliver to
+ your webhook
+
+ **Webhook Delivery:**
+
+ - We POST to your `callback_url` with JSON body containing files (matching
+ EmailCASFile schema)
+ - Failed deliveries are retried automatically with exponential backoff
+
+ **Inactivity:**
+
+ - Inbound emails with no activity in 30 days are marked inactive
+ - Active inbound emails remain operational indefinitely
+
+ Args:
+ callback_url: Webhook URL where we POST email notifications. Must be HTTPS in production (HTTP
+ allowed for localhost during development).
+
+ alias: Optional custom email prefix for user-friendly addresses.
+
+ - Must be 3-32 characters
+ - Alphanumeric + hyphens only
+ - Must start and end with letter/number
+ - Example: `john-portfolio@import.casparser.in`
+ - If omitted, generates random ID like `ie_abc123xyz@import.casparser.in`
+
+ allowed_sources: Filter emails by CAS provider. If omitted, accepts all providers.
+
+ - `cdsl` → eCAS@cdslstatement.com
+ - `nsdl` → NSDL-CAS@nsdl.co.in
+ - `cams` → donotreply@camsonline.com
+ - `kfintech` → samfS@kfintech.com
+
+ metadata: Optional key-value pairs (max 10) to include in webhook payload. Useful for
+ passing context like plan_type, campaign_id, etc.
+
+ reference: Your internal identifier (e.g., user_id, account_id). Returned in webhook
+ payload for correlation.
+
+ 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(
+ "/v4/inbound-email",
+ body=await async_maybe_transform(
+ {
+ "callback_url": callback_url,
+ "alias": alias,
+ "allowed_sources": allowed_sources,
+ "metadata": metadata,
+ "reference": reference,
+ },
+ inbound_email_create_params.InboundEmailCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=InboundEmailCreateResponse,
+ )
+
+ async def retrieve(
+ self,
+ inbound_email_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,
+ ) -> InboundEmailRetrieveResponse:
+ """
+ Retrieve details of a specific mailbox including statistics.
+
+ 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 inbound_email_id:
+ raise ValueError(f"Expected a non-empty value for `inbound_email_id` but received {inbound_email_id!r}")
+ return await self._get(
+ f"/v4/inbound-email/{inbound_email_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=InboundEmailRetrieveResponse,
+ )
+
+ async def list(
+ self,
+ *,
+ limit: int | Omit = omit,
+ offset: int | Omit = omit,
+ status: Literal["active", "paused", "all"] | 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,
+ ) -> InboundEmailListResponse:
+ """List all mailboxes associated with your API key.
+
+ Returns active and inactive
+ mailboxes (deleted mailboxes are excluded).
+
+ Args:
+ limit: Maximum number of inbound emails to return
+
+ offset: Pagination offset
+
+ status: Filter by status
+
+ 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(
+ "/v4/inbound-email",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "limit": limit,
+ "offset": offset,
+ "status": status,
+ },
+ inbound_email_list_params.InboundEmailListParams,
+ ),
+ ),
+ cast_to=InboundEmailListResponse,
+ )
+
+ async def delete(
+ self,
+ inbound_email_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,
+ ) -> InboundEmailDeleteResponse:
+ """Permanently delete an inbound email address.
+
+ It will stop accepting emails.
+
+ **Note:** Deletion is immediate and cannot be undone. Any emails received after
+ deletion will be rejected.
+
+ 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 inbound_email_id:
+ raise ValueError(f"Expected a non-empty value for `inbound_email_id` but received {inbound_email_id!r}")
+ return await self._delete(
+ f"/v4/inbound-email/{inbound_email_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=InboundEmailDeleteResponse,
+ )
+
+
+class InboundEmailResourceWithRawResponse:
+ def __init__(self, inbound_email: InboundEmailResource) -> None:
+ self._inbound_email = inbound_email
+
+ self.create = to_raw_response_wrapper(
+ inbound_email.create,
+ )
+ self.retrieve = to_raw_response_wrapper(
+ inbound_email.retrieve,
+ )
+ self.list = to_raw_response_wrapper(
+ inbound_email.list,
+ )
+ self.delete = to_raw_response_wrapper(
+ inbound_email.delete,
+ )
+
+
+class AsyncInboundEmailResourceWithRawResponse:
+ def __init__(self, inbound_email: AsyncInboundEmailResource) -> None:
+ self._inbound_email = inbound_email
+
+ self.create = async_to_raw_response_wrapper(
+ inbound_email.create,
+ )
+ self.retrieve = async_to_raw_response_wrapper(
+ inbound_email.retrieve,
+ )
+ self.list = async_to_raw_response_wrapper(
+ inbound_email.list,
+ )
+ self.delete = async_to_raw_response_wrapper(
+ inbound_email.delete,
+ )
+
+
+class InboundEmailResourceWithStreamingResponse:
+ def __init__(self, inbound_email: InboundEmailResource) -> None:
+ self._inbound_email = inbound_email
+
+ self.create = to_streamed_response_wrapper(
+ inbound_email.create,
+ )
+ self.retrieve = to_streamed_response_wrapper(
+ inbound_email.retrieve,
+ )
+ self.list = to_streamed_response_wrapper(
+ inbound_email.list,
+ )
+ self.delete = to_streamed_response_wrapper(
+ inbound_email.delete,
+ )
+
+
+class AsyncInboundEmailResourceWithStreamingResponse:
+ def __init__(self, inbound_email: AsyncInboundEmailResource) -> None:
+ self._inbound_email = inbound_email
+
+ self.create = async_to_streamed_response_wrapper(
+ inbound_email.create,
+ )
+ self.retrieve = async_to_streamed_response_wrapper(
+ inbound_email.retrieve,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ inbound_email.list,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ inbound_email.delete,
+ )
diff --git a/src/cas_parser/resources/logs.py b/src/cas_parser/resources/logs.py
index bd6ec9b..45ba056 100644
--- a/src/cas_parser/resources/logs.py
+++ b/src/cas_parser/resources/logs.py
@@ -64,6 +64,8 @@ def create(
Returns a list of API calls with timestamps, features used, status codes, and
credits consumed. Useful for monitoring usage patterns and debugging.
+ **Legacy path:** `/logs` (still supported)
+
Args:
end_time: End time filter (ISO 8601). Defaults to now.
@@ -80,7 +82,7 @@ def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
return self._post(
- "/logs",
+ "/v1/usage",
body=maybe_transform(
{
"end_time": end_time,
@@ -113,6 +115,8 @@ def get_summary(
Useful for understanding which API features are being used most and tracking
usage trends.
+ **Legacy path:** `/logs/summary` (still supported)
+
Args:
end_time: End time filter (ISO 8601). Defaults to now.
@@ -127,7 +131,7 @@ def get_summary(
timeout: Override the client-level default timeout for this request, in seconds
"""
return self._post(
- "/logs/summary",
+ "/v1/usage/summary",
body=maybe_transform(
{
"end_time": end_time,
@@ -181,6 +185,8 @@ async def create(
Returns a list of API calls with timestamps, features used, status codes, and
credits consumed. Useful for monitoring usage patterns and debugging.
+ **Legacy path:** `/logs` (still supported)
+
Args:
end_time: End time filter (ISO 8601). Defaults to now.
@@ -197,7 +203,7 @@ async def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
return await self._post(
- "/logs",
+ "/v1/usage",
body=await async_maybe_transform(
{
"end_time": end_time,
@@ -230,6 +236,8 @@ async def get_summary(
Useful for understanding which API features are being used most and tracking
usage trends.
+ **Legacy path:** `/logs/summary` (still supported)
+
Args:
end_time: End time filter (ISO 8601). Defaults to now.
@@ -244,7 +252,7 @@ async def get_summary(
timeout: Override the client-level default timeout for this request, in seconds
"""
return await self._post(
- "/logs/summary",
+ "/v1/usage/summary",
body=await async_maybe_transform(
{
"end_time": end_time,
diff --git a/src/cas_parser/resources/verify_token.py b/src/cas_parser/resources/verify_token.py
index 273eb62..06981d4 100644
--- a/src/cas_parser/resources/verify_token.py
+++ b/src/cas_parser/resources/verify_token.py
@@ -55,7 +55,7 @@ def verify(
issues.
"""
return self._post(
- "/v1/verify-token",
+ "/v1/token/verify",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -99,7 +99,7 @@ async def verify(
issues.
"""
return await self._post(
- "/v1/verify-token",
+ "/v1/token/verify",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
diff --git a/src/cas_parser/types/__init__.py b/src/cas_parser/types/__init__.py
index d72939a..269b048 100644
--- a/src/cas_parser/types/__init__.py
+++ b/src/cas_parser/types/__init__.py
@@ -12,19 +12,25 @@
from .credit_check_response import CreditCheckResponse as CreditCheckResponse
from .log_get_summary_params import LogGetSummaryParams as LogGetSummaryParams
from .log_get_summary_response import LogGetSummaryResponse as LogGetSummaryResponse
+from .inbound_email_list_params import InboundEmailListParams as InboundEmailListParams
from .access_token_create_params import AccessTokenCreateParams as AccessTokenCreateParams
from .cams_kfintech_parse_params import CamsKfintechParseParams as CamsKfintechParseParams
from .contract_note_parse_params import ContractNoteParseParams as ContractNoteParseParams
from .inbox_connect_email_params import InboxConnectEmailParams as InboxConnectEmailParams
from .smart_parse_cas_pdf_params import SmartParseCasPdfParams as SmartParseCasPdfParams
+from .inbound_email_create_params import InboundEmailCreateParams as InboundEmailCreateParams
+from .inbound_email_list_response import InboundEmailListResponse as InboundEmailListResponse
from .inbox_list_cas_files_params import InboxListCasFilesParams as InboxListCasFilesParams
from .access_token_create_response import AccessTokenCreateResponse as AccessTokenCreateResponse
from .contract_note_parse_response import ContractNoteParseResponse as ContractNoteParseResponse
from .inbox_connect_email_response import InboxConnectEmailResponse as InboxConnectEmailResponse
from .kfintech_generate_cas_params import KfintechGenerateCasParams as KfintechGenerateCasParams
from .verify_token_verify_response import VerifyTokenVerifyResponse as VerifyTokenVerifyResponse
+from .inbound_email_create_response import InboundEmailCreateResponse as InboundEmailCreateResponse
+from .inbound_email_delete_response import InboundEmailDeleteResponse as InboundEmailDeleteResponse
from .inbox_list_cas_files_response import InboxListCasFilesResponse as InboxListCasFilesResponse
from .kfintech_generate_cas_response import KfintechGenerateCasResponse as KfintechGenerateCasResponse
+from .inbound_email_retrieve_response import InboundEmailRetrieveResponse as InboundEmailRetrieveResponse
from .inbox_disconnect_email_response import InboxDisconnectEmailResponse as InboxDisconnectEmailResponse
from .inbox_check_connection_status_response import (
InboxCheckConnectionStatusResponse as InboxCheckConnectionStatusResponse,
diff --git a/src/cas_parser/types/inbound_email_create_params.py b/src/cas_parser/types/inbound_email_create_params.py
new file mode 100644
index 0000000..356d7e1
--- /dev/null
+++ b/src/cas_parser/types/inbound_email_create_params.py
@@ -0,0 +1,47 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, List
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["InboundEmailCreateParams"]
+
+
+class InboundEmailCreateParams(TypedDict, total=False):
+ callback_url: Required[str]
+ """
+ Webhook URL where we POST email notifications. Must be HTTPS in production (HTTP
+ allowed for localhost during development).
+ """
+
+ alias: str
+ """Optional custom email prefix for user-friendly addresses.
+
+ - Must be 3-32 characters
+ - Alphanumeric + hyphens only
+ - Must start and end with letter/number
+ - Example: `john-portfolio@import.casparser.in`
+ - If omitted, generates random ID like `ie_abc123xyz@import.casparser.in`
+ """
+
+ allowed_sources: List[Literal["cdsl", "nsdl", "cams", "kfintech"]]
+ """Filter emails by CAS provider. If omitted, accepts all providers.
+
+ - `cdsl` → eCAS@cdslstatement.com
+ - `nsdl` → NSDL-CAS@nsdl.co.in
+ - `cams` → donotreply@camsonline.com
+ - `kfintech` → samfS@kfintech.com
+ """
+
+ metadata: Dict[str, str]
+ """
+ Optional key-value pairs (max 10) to include in webhook payload. Useful for
+ passing context like plan_type, campaign_id, etc.
+ """
+
+ reference: str
+ """
+ Your internal identifier (e.g., user_id, account_id). Returned in webhook
+ payload for correlation.
+ """
diff --git a/src/cas_parser/types/inbound_email_create_response.py b/src/cas_parser/types/inbound_email_create_response.py
new file mode 100644
index 0000000..29f89dc
--- /dev/null
+++ b/src/cas_parser/types/inbound_email_create_response.py
@@ -0,0 +1,40 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict, List, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["InboundEmailCreateResponse"]
+
+
+class InboundEmailCreateResponse(BaseModel):
+ """An inbound email address for receiving forwarded CAS emails"""
+
+ allowed_sources: Optional[List[Literal["cdsl", "nsdl", "cams", "kfintech"]]] = None
+ """Accepted CAS providers (empty = all)"""
+
+ callback_url: Optional[str] = None
+ """Webhook URL for email notifications"""
+
+ created_at: Optional[datetime] = None
+ """When the mailbox was created"""
+
+ email: Optional[str] = None
+ """The inbound email address to forward CAS statements to"""
+
+ inbound_email_id: Optional[str] = None
+ """Unique inbound email identifier"""
+
+ metadata: Optional[Dict[str, str]] = None
+ """Custom key-value metadata"""
+
+ reference: Optional[str] = None
+ """Your internal reference identifier"""
+
+ status: Optional[Literal["active", "paused"]] = None
+ """Current mailbox status"""
+
+ updated_at: Optional[datetime] = None
+ """When the mailbox was last updated"""
diff --git a/src/cas_parser/types/inbound_email_delete_response.py b/src/cas_parser/types/inbound_email_delete_response.py
new file mode 100644
index 0000000..fdb55b2
--- /dev/null
+++ b/src/cas_parser/types/inbound_email_delete_response.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+
+from .._models import BaseModel
+
+__all__ = ["InboundEmailDeleteResponse"]
+
+
+class InboundEmailDeleteResponse(BaseModel):
+ msg: Optional[str] = None
+
+ status: Optional[str] = None
diff --git a/src/cas_parser/types/inbound_email_list_params.py b/src/cas_parser/types/inbound_email_list_params.py
new file mode 100644
index 0000000..c70d034
--- /dev/null
+++ b/src/cas_parser/types/inbound_email_list_params.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, TypedDict
+
+__all__ = ["InboundEmailListParams"]
+
+
+class InboundEmailListParams(TypedDict, total=False):
+ limit: int
+ """Maximum number of inbound emails to return"""
+
+ offset: int
+ """Pagination offset"""
+
+ status: Literal["active", "paused", "all"]
+ """Filter by status"""
diff --git a/src/cas_parser/types/inbound_email_list_response.py b/src/cas_parser/types/inbound_email_list_response.py
new file mode 100644
index 0000000..b1eea1b
--- /dev/null
+++ b/src/cas_parser/types/inbound_email_list_response.py
@@ -0,0 +1,53 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict, List, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["InboundEmailListResponse", "InboundEmail"]
+
+
+class InboundEmail(BaseModel):
+ """An inbound email address for receiving forwarded CAS emails"""
+
+ allowed_sources: Optional[List[Literal["cdsl", "nsdl", "cams", "kfintech"]]] = None
+ """Accepted CAS providers (empty = all)"""
+
+ callback_url: Optional[str] = None
+ """Webhook URL for email notifications"""
+
+ created_at: Optional[datetime] = None
+ """When the mailbox was created"""
+
+ email: Optional[str] = None
+ """The inbound email address to forward CAS statements to"""
+
+ inbound_email_id: Optional[str] = None
+ """Unique inbound email identifier"""
+
+ metadata: Optional[Dict[str, str]] = None
+ """Custom key-value metadata"""
+
+ reference: Optional[str] = None
+ """Your internal reference identifier"""
+
+ status: Optional[Literal["active", "paused"]] = None
+ """Current mailbox status"""
+
+ updated_at: Optional[datetime] = None
+ """When the mailbox was last updated"""
+
+
+class InboundEmailListResponse(BaseModel):
+ inbound_emails: Optional[List[InboundEmail]] = None
+
+ limit: Optional[int] = None
+
+ offset: Optional[int] = None
+
+ status: Optional[str] = None
+
+ total: Optional[int] = None
+ """Total number of inbound emails (for pagination)"""
diff --git a/src/cas_parser/types/inbound_email_retrieve_response.py b/src/cas_parser/types/inbound_email_retrieve_response.py
new file mode 100644
index 0000000..601fc87
--- /dev/null
+++ b/src/cas_parser/types/inbound_email_retrieve_response.py
@@ -0,0 +1,40 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict, List, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["InboundEmailRetrieveResponse"]
+
+
+class InboundEmailRetrieveResponse(BaseModel):
+ """An inbound email address for receiving forwarded CAS emails"""
+
+ allowed_sources: Optional[List[Literal["cdsl", "nsdl", "cams", "kfintech"]]] = None
+ """Accepted CAS providers (empty = all)"""
+
+ callback_url: Optional[str] = None
+ """Webhook URL for email notifications"""
+
+ created_at: Optional[datetime] = None
+ """When the mailbox was created"""
+
+ email: Optional[str] = None
+ """The inbound email address to forward CAS statements to"""
+
+ inbound_email_id: Optional[str] = None
+ """Unique inbound email identifier"""
+
+ metadata: Optional[Dict[str, str]] = None
+ """Custom key-value metadata"""
+
+ reference: Optional[str] = None
+ """Your internal reference identifier"""
+
+ status: Optional[Literal["active", "paused"]] = None
+ """Current mailbox status"""
+
+ updated_at: Optional[datetime] = None
+ """When the mailbox was last updated"""
diff --git a/src/cas_parser/types/inbox_list_cas_files_response.py b/src/cas_parser/types/inbox_list_cas_files_response.py
index ef27d92..25b960f 100644
--- a/src/cas_parser/types/inbox_list_cas_files_response.py
+++ b/src/cas_parser/types/inbox_list_cas_files_response.py
@@ -30,6 +30,12 @@ class File(BaseModel):
original_filename: Optional[str] = None
"""Original attachment filename from the email"""
+ sender_email: Optional[str] = None
+ """
+ Email address of the CAS authority (CDSL, NSDL, CAMS, or KFintech) who
+ originally sent this statement
+ """
+
size: Optional[int] = None
"""File size in bytes"""
diff --git a/tests/api_resources/test_inbound_email.py b/tests/api_resources/test_inbound_email.py
new file mode 100644
index 0000000..6970229
--- /dev/null
+++ b/tests/api_resources/test_inbound_email.py
@@ -0,0 +1,371 @@
+# 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 cas_parser import CasParser, AsyncCasParser
+from tests.utils import assert_matches_type
+from cas_parser.types import (
+ InboundEmailListResponse,
+ InboundEmailCreateResponse,
+ InboundEmailDeleteResponse,
+ InboundEmailRetrieveResponse,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestInboundEmail:
+ 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: CasParser) -> None:
+ inbound_email = client.inbound_email.create(
+ callback_url="https://api.yourapp.com/webhooks/cas-email",
+ )
+ assert_matches_type(InboundEmailCreateResponse, inbound_email, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_create_with_all_params(self, client: CasParser) -> None:
+ inbound_email = client.inbound_email.create(
+ callback_url="https://api.yourapp.com/webhooks/cas-email",
+ alias="john-portfolio",
+ allowed_sources=["cdsl", "nsdl"],
+ metadata={
+ "plan": "premium",
+ "source": "onboarding",
+ },
+ reference="user_12345",
+ )
+ assert_matches_type(InboundEmailCreateResponse, inbound_email, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_create(self, client: CasParser) -> None:
+ response = client.inbound_email.with_raw_response.create(
+ callback_url="https://api.yourapp.com/webhooks/cas-email",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ inbound_email = response.parse()
+ assert_matches_type(InboundEmailCreateResponse, inbound_email, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_create(self, client: CasParser) -> None:
+ with client.inbound_email.with_streaming_response.create(
+ callback_url="https://api.yourapp.com/webhooks/cas-email",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ inbound_email = response.parse()
+ assert_matches_type(InboundEmailCreateResponse, inbound_email, 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: CasParser) -> None:
+ inbound_email = client.inbound_email.retrieve(
+ "ie_a1b2c3d4e5f6",
+ )
+ assert_matches_type(InboundEmailRetrieveResponse, inbound_email, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_retrieve(self, client: CasParser) -> None:
+ response = client.inbound_email.with_raw_response.retrieve(
+ "ie_a1b2c3d4e5f6",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ inbound_email = response.parse()
+ assert_matches_type(InboundEmailRetrieveResponse, inbound_email, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_retrieve(self, client: CasParser) -> None:
+ with client.inbound_email.with_streaming_response.retrieve(
+ "ie_a1b2c3d4e5f6",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ inbound_email = response.parse()
+ assert_matches_type(InboundEmailRetrieveResponse, inbound_email, 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: CasParser) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbound_email_id` but received ''"):
+ client.inbound_email.with_raw_response.retrieve(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list(self, client: CasParser) -> None:
+ inbound_email = client.inbound_email.list()
+ assert_matches_type(InboundEmailListResponse, inbound_email, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: CasParser) -> None:
+ inbound_email = client.inbound_email.list(
+ limit=1,
+ offset=0,
+ status="active",
+ )
+ assert_matches_type(InboundEmailListResponse, inbound_email, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: CasParser) -> None:
+ response = client.inbound_email.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ inbound_email = response.parse()
+ assert_matches_type(InboundEmailListResponse, inbound_email, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: CasParser) -> None:
+ with client.inbound_email.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ inbound_email = response.parse()
+ assert_matches_type(InboundEmailListResponse, inbound_email, 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: CasParser) -> None:
+ inbound_email = client.inbound_email.delete(
+ "inbound_email_id",
+ )
+ assert_matches_type(InboundEmailDeleteResponse, inbound_email, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_delete(self, client: CasParser) -> None:
+ response = client.inbound_email.with_raw_response.delete(
+ "inbound_email_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ inbound_email = response.parse()
+ assert_matches_type(InboundEmailDeleteResponse, inbound_email, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_delete(self, client: CasParser) -> None:
+ with client.inbound_email.with_streaming_response.delete(
+ "inbound_email_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ inbound_email = response.parse()
+ assert_matches_type(InboundEmailDeleteResponse, inbound_email, path=["response"])
+
+ 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: CasParser) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbound_email_id` but received ''"):
+ client.inbound_email.with_raw_response.delete(
+ "",
+ )
+
+
+class TestAsyncInboundEmail:
+ 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: AsyncCasParser) -> None:
+ inbound_email = await async_client.inbound_email.create(
+ callback_url="https://api.yourapp.com/webhooks/cas-email",
+ )
+ assert_matches_type(InboundEmailCreateResponse, inbound_email, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncCasParser) -> None:
+ inbound_email = await async_client.inbound_email.create(
+ callback_url="https://api.yourapp.com/webhooks/cas-email",
+ alias="john-portfolio",
+ allowed_sources=["cdsl", "nsdl"],
+ metadata={
+ "plan": "premium",
+ "source": "onboarding",
+ },
+ reference="user_12345",
+ )
+ assert_matches_type(InboundEmailCreateResponse, inbound_email, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncCasParser) -> None:
+ response = await async_client.inbound_email.with_raw_response.create(
+ callback_url="https://api.yourapp.com/webhooks/cas-email",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ inbound_email = await response.parse()
+ assert_matches_type(InboundEmailCreateResponse, inbound_email, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncCasParser) -> None:
+ async with async_client.inbound_email.with_streaming_response.create(
+ callback_url="https://api.yourapp.com/webhooks/cas-email",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ inbound_email = await response.parse()
+ assert_matches_type(InboundEmailCreateResponse, inbound_email, 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: AsyncCasParser) -> None:
+ inbound_email = await async_client.inbound_email.retrieve(
+ "ie_a1b2c3d4e5f6",
+ )
+ assert_matches_type(InboundEmailRetrieveResponse, inbound_email, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncCasParser) -> None:
+ response = await async_client.inbound_email.with_raw_response.retrieve(
+ "ie_a1b2c3d4e5f6",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ inbound_email = await response.parse()
+ assert_matches_type(InboundEmailRetrieveResponse, inbound_email, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncCasParser) -> None:
+ async with async_client.inbound_email.with_streaming_response.retrieve(
+ "ie_a1b2c3d4e5f6",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ inbound_email = await response.parse()
+ assert_matches_type(InboundEmailRetrieveResponse, inbound_email, 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: AsyncCasParser) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbound_email_id` but received ''"):
+ await async_client.inbound_email.with_raw_response.retrieve(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_list(self, async_client: AsyncCasParser) -> None:
+ inbound_email = await async_client.inbound_email.list()
+ assert_matches_type(InboundEmailListResponse, inbound_email, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncCasParser) -> None:
+ inbound_email = await async_client.inbound_email.list(
+ limit=1,
+ offset=0,
+ status="active",
+ )
+ assert_matches_type(InboundEmailListResponse, inbound_email, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncCasParser) -> None:
+ response = await async_client.inbound_email.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ inbound_email = await response.parse()
+ assert_matches_type(InboundEmailListResponse, inbound_email, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncCasParser) -> None:
+ async with async_client.inbound_email.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ inbound_email = await response.parse()
+ assert_matches_type(InboundEmailListResponse, inbound_email, 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: AsyncCasParser) -> None:
+ inbound_email = await async_client.inbound_email.delete(
+ "inbound_email_id",
+ )
+ assert_matches_type(InboundEmailDeleteResponse, inbound_email, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncCasParser) -> None:
+ response = await async_client.inbound_email.with_raw_response.delete(
+ "inbound_email_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ inbound_email = await response.parse()
+ assert_matches_type(InboundEmailDeleteResponse, inbound_email, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_delete(self, async_client: AsyncCasParser) -> None:
+ async with async_client.inbound_email.with_streaming_response.delete(
+ "inbound_email_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ inbound_email = await response.parse()
+ assert_matches_type(InboundEmailDeleteResponse, inbound_email, 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_delete(self, async_client: AsyncCasParser) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbound_email_id` but received ''"):
+ await async_client.inbound_email.with_raw_response.delete(
+ "",
+ )
diff --git a/tests/test_client.py b/tests/test_client.py
index ef1fd91..5a768aa 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -863,7 +863,7 @@ def test_parse_retry_after_header(
@mock.patch("cas_parser._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, client: CasParser) -> None:
- respx_mock.post("/credits").mock(side_effect=httpx.TimeoutException("Test timeout error"))
+ respx_mock.post("/v1/credits").mock(side_effect=httpx.TimeoutException("Test timeout error"))
with pytest.raises(APITimeoutError):
client.credits.with_streaming_response.check().__enter__()
@@ -873,7 +873,7 @@ def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, clien
@mock.patch("cas_parser._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client: CasParser) -> None:
- respx_mock.post("/credits").mock(return_value=httpx.Response(500))
+ respx_mock.post("/v1/credits").mock(return_value=httpx.Response(500))
with pytest.raises(APIStatusError):
client.credits.with_streaming_response.check().__enter__()
@@ -903,7 +903,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.post("/credits").mock(side_effect=retry_handler)
+ respx_mock.post("/v1/credits").mock(side_effect=retry_handler)
response = client.credits.with_raw_response.check()
@@ -927,7 +927,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.post("/credits").mock(side_effect=retry_handler)
+ respx_mock.post("/v1/credits").mock(side_effect=retry_handler)
response = client.credits.with_raw_response.check(extra_headers={"x-stainless-retry-count": Omit()})
@@ -950,7 +950,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.post("/credits").mock(side_effect=retry_handler)
+ respx_mock.post("/v1/credits").mock(side_effect=retry_handler)
response = client.credits.with_raw_response.check(extra_headers={"x-stainless-retry-count": "42"})
@@ -1775,7 +1775,7 @@ async def test_parse_retry_after_header(
async def test_retrying_timeout_errors_doesnt_leak(
self, respx_mock: MockRouter, async_client: AsyncCasParser
) -> None:
- respx_mock.post("/credits").mock(side_effect=httpx.TimeoutException("Test timeout error"))
+ respx_mock.post("/v1/credits").mock(side_effect=httpx.TimeoutException("Test timeout error"))
with pytest.raises(APITimeoutError):
await async_client.credits.with_streaming_response.check().__aenter__()
@@ -1787,7 +1787,7 @@ async def test_retrying_timeout_errors_doesnt_leak(
async def test_retrying_status_errors_doesnt_leak(
self, respx_mock: MockRouter, async_client: AsyncCasParser
) -> None:
- respx_mock.post("/credits").mock(return_value=httpx.Response(500))
+ respx_mock.post("/v1/credits").mock(return_value=httpx.Response(500))
with pytest.raises(APIStatusError):
await async_client.credits.with_streaming_response.check().__aenter__()
@@ -1817,7 +1817,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.post("/credits").mock(side_effect=retry_handler)
+ respx_mock.post("/v1/credits").mock(side_effect=retry_handler)
response = await client.credits.with_raw_response.check()
@@ -1841,7 +1841,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.post("/credits").mock(side_effect=retry_handler)
+ respx_mock.post("/v1/credits").mock(side_effect=retry_handler)
response = await client.credits.with_raw_response.check(extra_headers={"x-stainless-retry-count": Omit()})
@@ -1864,7 +1864,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.post("/credits").mock(side_effect=retry_handler)
+ respx_mock.post("/v1/credits").mock(side_effect=retry_handler)
response = await client.credits.with_raw_response.check(extra_headers={"x-stainless-retry-count": "42"})