diff --git a/.spec-sha b/.spec-sha
index 7dd08d4..567f72b 100644
--- a/.spec-sha
+++ b/.spec-sha
@@ -1 +1 @@
-6ace098c56527cf0a0e5018b67ec454412ee6926
+1e2fe608c41aefd1a51cd3701be42db3f41730c8
diff --git a/src/onepin/.fern/metadata.json b/src/onepin/.fern/metadata.json
index 6f11267..da28c6e 100644
--- a/src/onepin/.fern/metadata.json
+++ b/src/onepin/.fern/metadata.json
@@ -30,7 +30,7 @@
}
]
},
- "originGitCommit": "9e634eff3eb65ab32b4a77b6fee5e0d27aa126cf",
+ "originGitCommit": "8161f2e78f880139a10f4fbd560a506103452095",
"originGitCommitIsDirty": false,
"invokedBy": "ci",
"ciProvider": "github"
diff --git a/src/onepin/__init__.py b/src/onepin/__init__.py
index 3fa3327..5543d6d 100644
--- a/src/onepin/__init__.py
+++ b/src/onepin/__init__.py
@@ -98,6 +98,7 @@
NumericOption,
PaginationMeta,
PlanLimits,
+ PlanLimitsCreditsRenewal,
PlanTier,
PortOut,
PronunciationSuggestion,
@@ -368,6 +369,7 @@
"OnepinClient": "._client",
"PaginationMeta": ".types",
"PlanLimits": ".types",
+ "PlanLimitsCreditsRenewal": ".types",
"PlanTier": ".types",
"PortOut": ".types",
"PronunciationSuggestion": ".types",
@@ -639,6 +641,7 @@ def __dir__():
"OnepinClient",
"PaginationMeta",
"PlanLimits",
+ "PlanLimitsCreditsRenewal",
"PlanTier",
"PortOut",
"PronunciationSuggestion",
diff --git a/src/onepin/dictionary/types/list_dictionary_entries_api_v1dictionary_get_request_language.py b/src/onepin/dictionary/types/list_dictionary_entries_api_v1dictionary_get_request_language.py
index a062a7d..225635d 100644
--- a/src/onepin/dictionary/types/list_dictionary_entries_api_v1dictionary_get_request_language.py
+++ b/src/onepin/dictionary/types/list_dictionary_entries_api_v1dictionary_get_request_language.py
@@ -3,5 +3,6 @@
import typing
ListDictionaryEntriesApiV1DictionaryGetRequestLanguage = typing.Union[
- typing.Literal["de-de", "en-gb", "en-us", "es-es", "fr-fr", "it-it", "ja-jp", "ko-kr", "pt-br", "zh-cn"], typing.Any
+ typing.Literal["de-de", "en-gb", "en-us", "es-es", "es-mx", "fr-fr", "ja-jp", "ko-kr", "pt-br", "pt-pt", "zh-cn"],
+ typing.Any,
]
diff --git a/src/onepin/dictionary/types/search_dictionary_entries_api_v1dictionary_search_get_request_language_item.py b/src/onepin/dictionary/types/search_dictionary_entries_api_v1dictionary_search_get_request_language_item.py
index 91bec6a..52ef385 100644
--- a/src/onepin/dictionary/types/search_dictionary_entries_api_v1dictionary_search_get_request_language_item.py
+++ b/src/onepin/dictionary/types/search_dictionary_entries_api_v1dictionary_search_get_request_language_item.py
@@ -3,5 +3,6 @@
import typing
SearchDictionaryEntriesApiV1DictionarySearchGetRequestLanguageItem = typing.Union[
- typing.Literal["de-de", "en-gb", "en-us", "es-es", "fr-fr", "it-it", "ja-jp", "ko-kr", "pt-br", "zh-cn"], typing.Any
+ typing.Literal["de-de", "en-gb", "en-us", "es-es", "es-mx", "fr-fr", "ja-jp", "ko-kr", "pt-br", "pt-pt", "zh-cn"],
+ typing.Any,
]
diff --git a/src/onepin/reference.md b/src/onepin/reference.md
index 0271a82..ccdb161 100644
--- a/src/onepin/reference.md
+++ b/src/onepin/reference.md
@@ -2682,7 +2682,7 @@ client.voices.list()
-
-**search:** `typing.Optional[str]` — Full-text search against voice name, description, and tags.
+**search:** `typing.Optional[str]` — Searches name, tags, and the voice's summary-derived descriptor text (closely tracks the served description; summary beyond 200 chars is not searched).
@@ -5316,9 +5316,14 @@ attempt a workflow run. `remaining` is a display convenience derived from
settled ledger entries and may temporarily exceed `balance` while a workflow
run holds an open reserve. `used` reflects credits consumed in the current
billing period. `plan_grant` is the total monthly credit allowance for the
-caller's plan, enabling a "X / Y used" display. `period_start` and
-`period_end` mark the boundaries of the current billing window; free-tier
-callers use a calendar-month boundary.
+caller's plan, enabling a "X / Y used" display. `period_start` is the current
+credit anchor and `period_end` is the next EXPECTED credit-reset boundary
+(`period_start` + 1 month), or null when no reset is promised — Free/one-time,
+unanchored, a canceling/ended entitlement, or a monthly renewal whose boundary
+passed without confirmed payment. `period_end` is the expected boundary, not a
+guaranteed grant time: monthly credits stay gated on successful Stripe payment.
+For an annual subscriber this GET may perform idempotent maintenance, granting
+any due intermediate monthly credits before returning; retries remain safe.
diff --git a/src/onepin/types/__init__.py b/src/onepin/types/__init__.py
index c2f5808..48dd18f 100644
--- a/src/onepin/types/__init__.py
+++ b/src/onepin/types/__init__.py
@@ -99,6 +99,7 @@
from .numeric_option import NumericOption
from .pagination_meta import PaginationMeta
from .plan_limits import PlanLimits
+ from .plan_limits_credits_renewal import PlanLimitsCreditsRenewal
from .plan_tier import PlanTier
from .port_out import PortOut
from .pronunciation_suggestion import PronunciationSuggestion
@@ -295,6 +296,7 @@
"NumericOption": ".numeric_option",
"PaginationMeta": ".pagination_meta",
"PlanLimits": ".plan_limits",
+ "PlanLimitsCreditsRenewal": ".plan_limits_credits_renewal",
"PlanTier": ".plan_tier",
"PortOut": ".port_out",
"PronunciationSuggestion": ".pronunciation_suggestion",
@@ -515,6 +517,7 @@ def __dir__():
"NumericOption",
"PaginationMeta",
"PlanLimits",
+ "PlanLimitsCreditsRenewal",
"PlanTier",
"PortOut",
"PronunciationSuggestion",
diff --git a/src/onepin/types/api_error_detail.py b/src/onepin/types/api_error_detail.py
index 8b6b8eb..1c95971 100644
--- a/src/onepin/types/api_error_detail.py
+++ b/src/onepin/types/api_error_detail.py
@@ -9,6 +9,8 @@
class ApiErrorDetail(UniversalBaseModel):
field: str
message: str
+ line_numbers: typing.Optional[typing.List[int]] = None
+ min_chars: typing.Optional[int] = None
if IS_PYDANTIC_V2:
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
diff --git a/src/onepin/types/balance_response.py b/src/onepin/types/balance_response.py
index 18e36c6..6a77746 100644
--- a/src/onepin/types/balance_response.py
+++ b/src/onepin/types/balance_response.py
@@ -13,7 +13,26 @@ class BalanceResponse(UniversalBaseModel):
Per-user credit balance + period anchor (consumed by GET /users/me/credits).
"""
- balance: int
+ balance: int = pydantic.Field()
+ """
+ Total spendable credits = monthly_balance + free_balance.
+ """
+
+ monthly_balance: typing.Optional[int] = pydantic.Field(default=None)
+ """
+ Expiring bucket: the current paid cycle's allowance, replaced each renewal. 0 on Free.
+ """
+
+ free_balance: typing.Optional[int] = pydantic.Field(default=None)
+ """
+ Lifetime bucket: the one-time Free grant. Never expires; spent last (after monthly).
+ """
+
+ free_grant: typing.Optional[int] = pydantic.Field(default=None)
+ """
+ All-time ceiling of the lifetime free bucket.
+ """
+
used: typing.Optional[int] = pydantic.Field(default=None)
"""
Ledger-derived credits used in the current billing period.
@@ -24,10 +43,28 @@ class BalanceResponse(UniversalBaseModel):
Ledger-derived settled credits remaining for display only. Excludes in-flight open reserves, so this may exceed `balance` while a workflow is executing. Use `balance` for gate decisions.
"""
- period_start: typing.Optional[dt.datetime] = None
- period_end: typing.Optional[dt.datetime] = None
+ period_start: typing.Optional[dt.datetime] = pydantic.Field(default=None)
+ """
+ Start of the current credit period (the stored credit anchor). Null on Free/unanchored accounts.
+ """
+
+ period_end: typing.Optional[dt.datetime] = pydantic.Field(default=None)
+ """
+ Next EXPECTED credit-reset boundary (`period_start` + 1 calendar month), or null when no reset is currently promised: Free/one-time or unanchored accounts, a canceling/ended entitlement with no future grant, or a monthly renewal whose boundary has already passed without confirmed payment. This is the expected boundary, not a guaranteed grant time — monthly credits (including an annual subscription's renewal) stay gated on successful Stripe payment and may become available shortly after this time. An annual subscription's intermediate monthly boundaries are deterministic and are granted on access. Distinct from `CustomerSubscriptionResponse.current_period_end`, which remains the Stripe billing/entitlement boundary and must not be used as the credit-refresh time.
+ """
+
plan_grant: int
plan_tier: PlanTier
+ overage_rate_cents_per_credit: typing.Optional[float] = None
+ overage_cents: typing.Optional[int] = pydantic.Field(default=None)
+ """
+ Overage billed so far this billing cycle, in cents.
+ """
+
+ credits_absorbed: typing.Optional[float] = pydantic.Field(default=None)
+ """
+ Total credits discounted by floor-rounding this billing period.
+ """
if IS_PYDANTIC_V2:
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
diff --git a/src/onepin/types/estimate_response.py b/src/onepin/types/estimate_response.py
index d17cae6..bdede5b 100644
--- a/src/onepin/types/estimate_response.py
+++ b/src/onepin/types/estimate_response.py
@@ -22,6 +22,9 @@ class EstimateResponse(UniversalBaseModel):
current_balance: int
deficit_at_max: int
can_run: bool
+ overage_rate_cents_per_credit: typing.Optional[float] = None
+ will_incur_overage: typing.Optional[bool] = None
+ estimated_overage_cents: typing.Optional[int] = None
if IS_PYDANTIC_V2:
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
diff --git a/src/onepin/types/plan_limits.py b/src/onepin/types/plan_limits.py
index 71c2c19..95d541c 100644
--- a/src/onepin/types/plan_limits.py
+++ b/src/onepin/types/plan_limits.py
@@ -4,6 +4,7 @@
import pydantic
from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .plan_limits_credits_renewal import PlanLimitsCreditsRenewal
class PlanLimits(UniversalBaseModel):
@@ -18,6 +19,9 @@ class PlanLimits(UniversalBaseModel):
retention_days: typing.Optional[int] = None
byok_enabled: typing.Optional[bool] = None
auto_fix_enabled: typing.Optional[bool] = None
+ credits_renewal: typing.Optional[PlanLimitsCreditsRenewal] = None
+ downloads_enabled: typing.Optional[bool] = None
+ overage_rate_cents_per_credit: typing.Optional[float] = None
if IS_PYDANTIC_V2:
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
diff --git a/src/onepin/types/plan_limits_credits_renewal.py b/src/onepin/types/plan_limits_credits_renewal.py
new file mode 100644
index 0000000..29af1b6
--- /dev/null
+++ b/src/onepin/types/plan_limits_credits_renewal.py
@@ -0,0 +1,5 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+PlanLimitsCreditsRenewal = typing.Union[typing.Literal["monthly", "one_time"], typing.Any]
diff --git a/src/onepin/types/voice_out.py b/src/onepin/types/voice_out.py
index c4e7610..3f736aa 100644
--- a/src/onepin/types/voice_out.py
+++ b/src/onepin/types/voice_out.py
@@ -73,11 +73,6 @@ class VoiceOut(UniversalBaseModel):
Freeform keyword tags for filtering and search.
"""
- descriptor: typing.Optional[str] = pydantic.Field(default=None)
- """
- Short one-line voice personality descriptor.
- """
-
uses_count: typing.Optional[int] = pydantic.Field(default=None)
"""
Number of times this voice has been used in workflow runs across the platform.
diff --git a/src/onepin/types/voice_similar_out.py b/src/onepin/types/voice_similar_out.py
index d20d6fe..bc97998 100644
--- a/src/onepin/types/voice_similar_out.py
+++ b/src/onepin/types/voice_similar_out.py
@@ -73,11 +73,6 @@ class VoiceSimilarOut(UniversalBaseModel):
Freeform keyword tags for filtering and search.
"""
- descriptor: typing.Optional[str] = pydantic.Field(default=None)
- """
- Short one-line voice personality descriptor.
- """
-
uses_count: typing.Optional[int] = pydantic.Field(default=None)
"""
Number of times this voice has been used in workflow runs across the platform.
diff --git a/src/onepin/types/workflow_run_detail_out.py b/src/onepin/types/workflow_run_detail_out.py
index f018add..8d4d115 100644
--- a/src/onepin/types/workflow_run_detail_out.py
+++ b/src/onepin/types/workflow_run_detail_out.py
@@ -36,6 +36,11 @@ class WorkflowRunDetailOut(UniversalBaseModel):
has_export: typing.Optional[bool] = None
triggered_by: typing.Optional[TriggeredByOut] = None
credits: typing.Optional[int] = None
+ credits_absorbed: typing.Optional[float] = pydantic.Field(default=None)
+ """
+ Credits discounted by floor-rounding for this run. This is the sub-credit remainder above the charged (floored) credits; charged credits plus this value reconstructs true cost only for fully covered, uncapped runs. Returns 0 for unsettled or legacy runs.
+ """
+
definition_snapshot: typing.Optional[typing.Dict[str, typing.Any]] = None
if IS_PYDANTIC_V2:
diff --git a/src/onepin/types/workflow_run_outputs_out.py b/src/onepin/types/workflow_run_outputs_out.py
index 73c4dcb..41e5554 100644
--- a/src/onepin/types/workflow_run_outputs_out.py
+++ b/src/onepin/types/workflow_run_outputs_out.py
@@ -11,6 +11,11 @@ class WorkflowRunOutputsOut(UniversalBaseModel):
run_id: str
run_status: str
credits: typing.Optional[int] = None
+ credits_absorbed: typing.Optional[float] = pydantic.Field(default=None)
+ """
+ Credits discounted by floor-rounding for this run. This is the sub-credit remainder above the charged (floored) credits; charged credits plus this value reconstructs true cost only for fully covered, uncapped runs. Returns 0 for unsettled or legacy runs.
+ """
+
outputs: typing.List[WorkflowRunSinkOutputOut]
if IS_PYDANTIC_V2:
diff --git a/src/onepin/users/client.py b/src/onepin/users/client.py
index 4de6674..e2a5d91 100644
--- a/src/onepin/users/client.py
+++ b/src/onepin/users/client.py
@@ -42,9 +42,14 @@ def get_my_credits(self, *, request_options: typing.Optional[RequestOptions] = N
settled ledger entries and may temporarily exceed `balance` while a workflow
run holds an open reserve. `used` reflects credits consumed in the current
billing period. `plan_grant` is the total monthly credit allowance for the
- caller's plan, enabling a "X / Y used" display. `period_start` and
- `period_end` mark the boundaries of the current billing window; free-tier
- callers use a calendar-month boundary.
+ caller's plan, enabling a "X / Y used" display. `period_start` is the current
+ credit anchor and `period_end` is the next EXPECTED credit-reset boundary
+ (`period_start` + 1 month), or null when no reset is promised — Free/one-time,
+ unanchored, a canceling/ended entitlement, or a monthly renewal whose boundary
+ passed without confirmed payment. `period_end` is the expected boundary, not a
+ guaranteed grant time: monthly credits stay gated on successful Stripe payment.
+ For an annual subscriber this GET may perform idempotent maintenance, granting
+ any due intermediate monthly credits before returning; retries remain safe.
Parameters
----------
@@ -276,9 +281,14 @@ async def get_my_credits(
settled ledger entries and may temporarily exceed `balance` while a workflow
run holds an open reserve. `used` reflects credits consumed in the current
billing period. `plan_grant` is the total monthly credit allowance for the
- caller's plan, enabling a "X / Y used" display. `period_start` and
- `period_end` mark the boundaries of the current billing window; free-tier
- callers use a calendar-month boundary.
+ caller's plan, enabling a "X / Y used" display. `period_start` is the current
+ credit anchor and `period_end` is the next EXPECTED credit-reset boundary
+ (`period_start` + 1 month), or null when no reset is promised — Free/one-time,
+ unanchored, a canceling/ended entitlement, or a monthly renewal whose boundary
+ passed without confirmed payment. `period_end` is the expected boundary, not a
+ guaranteed grant time: monthly credits stay gated on successful Stripe payment.
+ For an annual subscriber this GET may perform idempotent maintenance, granting
+ any due intermediate monthly credits before returning; retries remain safe.
Parameters
----------
diff --git a/src/onepin/users/raw_client.py b/src/onepin/users/raw_client.py
index 6da6376..d86b812 100644
--- a/src/onepin/users/raw_client.py
+++ b/src/onepin/users/raw_client.py
@@ -39,9 +39,14 @@ def get_my_credits(
settled ledger entries and may temporarily exceed `balance` while a workflow
run holds an open reserve. `used` reflects credits consumed in the current
billing period. `plan_grant` is the total monthly credit allowance for the
- caller's plan, enabling a "X / Y used" display. `period_start` and
- `period_end` mark the boundaries of the current billing window; free-tier
- callers use a calendar-month boundary.
+ caller's plan, enabling a "X / Y used" display. `period_start` is the current
+ credit anchor and `period_end` is the next EXPECTED credit-reset boundary
+ (`period_start` + 1 month), or null when no reset is promised — Free/one-time,
+ unanchored, a canceling/ended entitlement, or a monthly renewal whose boundary
+ passed without confirmed payment. `period_end` is the expected boundary, not a
+ guaranteed grant time: monthly credits stay gated on successful Stripe payment.
+ For an annual subscriber this GET may perform idempotent maintenance, granting
+ any due intermediate monthly credits before returning; retries remain safe.
Parameters
----------
@@ -385,9 +390,14 @@ async def get_my_credits(
settled ledger entries and may temporarily exceed `balance` while a workflow
run holds an open reserve. `used` reflects credits consumed in the current
billing period. `plan_grant` is the total monthly credit allowance for the
- caller's plan, enabling a "X / Y used" display. `period_start` and
- `period_end` mark the boundaries of the current billing window; free-tier
- callers use a calendar-month boundary.
+ caller's plan, enabling a "X / Y used" display. `period_start` is the current
+ credit anchor and `period_end` is the next EXPECTED credit-reset boundary
+ (`period_start` + 1 month), or null when no reset is promised — Free/one-time,
+ unanchored, a canceling/ended entitlement, or a monthly renewal whose boundary
+ passed without confirmed payment. `period_end` is the expected boundary, not a
+ guaranteed grant time: monthly credits stay gated on successful Stripe payment.
+ For an annual subscriber this GET may perform idempotent maintenance, granting
+ any due intermediate monthly credits before returning; retries remain safe.
Parameters
----------
diff --git a/src/onepin/voices/client.py b/src/onepin/voices/client.py
index 8ad7f77..b9e6cf4 100644
--- a/src/onepin/voices/client.py
+++ b/src/onepin/voices/client.py
@@ -107,7 +107,7 @@ def list(
Repeat for OR
search : typing.Optional[str]
- Full-text search against voice name, description, and tags.
+ Searches name, tags, and the voice's summary-derived descriptor text (closely tracks the served description; summary beyond 200 chars is not searched).
sort : typing.Optional[typing.Sequence[ListVoicesRequestSortItem]]
Repeat for multi-sort. Pairs with `order` index-wise.
@@ -556,7 +556,7 @@ async def list(
Repeat for OR
search : typing.Optional[str]
- Full-text search against voice name, description, and tags.
+ Searches name, tags, and the voice's summary-derived descriptor text (closely tracks the served description; summary beyond 200 chars is not searched).
sort : typing.Optional[typing.Sequence[ListVoicesRequestSortItem]]
Repeat for multi-sort. Pairs with `order` index-wise.
diff --git a/src/onepin/voices/raw_client.py b/src/onepin/voices/raw_client.py
index ecfef41..fc0752b 100644
--- a/src/onepin/voices/raw_client.py
+++ b/src/onepin/voices/raw_client.py
@@ -103,7 +103,7 @@ def list(
Repeat for OR
search : typing.Optional[str]
- Full-text search against voice name, description, and tags.
+ Searches name, tags, and the voice's summary-derived descriptor text (closely tracks the served description; summary beyond 200 chars is not searched).
sort : typing.Optional[typing.Sequence[ListVoicesRequestSortItem]]
Repeat for multi-sort. Pairs with `order` index-wise.
@@ -685,7 +685,7 @@ async def list(
Repeat for OR
search : typing.Optional[str]
- Full-text search against voice name, description, and tags.
+ Searches name, tags, and the voice's summary-derived descriptor text (closely tracks the served description; summary beyond 200 chars is not searched).
sort : typing.Optional[typing.Sequence[ListVoicesRequestSortItem]]
Repeat for multi-sort. Pairs with `order` index-wise.
diff --git a/src/onepin/voices/types/list_voices_request_language_item.py b/src/onepin/voices/types/list_voices_request_language_item.py
index 535d427..d2a3d6f 100644
--- a/src/onepin/voices/types/list_voices_request_language_item.py
+++ b/src/onepin/voices/types/list_voices_request_language_item.py
@@ -3,5 +3,6 @@
import typing
ListVoicesRequestLanguageItem = typing.Union[
- typing.Literal["de-de", "en-gb", "en-us", "es-es", "fr-fr", "it-it", "ja-jp", "ko-kr", "pt-br", "zh-cn"], typing.Any
+ typing.Literal["de-de", "en-gb", "en-us", "es-es", "es-mx", "fr-fr", "ja-jp", "ko-kr", "pt-br", "pt-pt", "zh-cn"],
+ typing.Any,
]