diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock
index 930764ec..3056541d 100644
--- a/.speakeasy/gen.lock
+++ b/.speakeasy/gen.lock
@@ -1,19 +1,19 @@
lockVersion: 2.0.0
id: c48cf606-fb42-4a45-9c23-8f0555307828
management:
- docChecksum: 54f6a56b3ce0196f24d04d18f37ab80a
+ docChecksum: 7021fe5b184fc767cdca7d6341eef638
docVersion: 1.0.0
speakeasyVersion: 1.803.2
generationVersion: 2.950.13
- releaseVersion: 1.3.104
- configChecksum: 1787fee2bed548acbc21c5c6887d812c
+ releaseVersion: 1.3.105
+ configChecksum: f6b1d0678e999163af01dfbaa9c23acc
repoURL: https://github.com/OpenRouterTeam/python-sdk.git
installationURL: https://github.com/OpenRouterTeam/python-sdk.git
published: true
persistentEdits:
- generation_id: 5f665d48-31fb-43ff-b17b-1f44c8e03e26
- pristine_commit_hash: 654fce46a3afc67527b658404a7a088531cfc0ca
- pristine_tree_hash: 54a0e2a6d89cfb8fa5c0985bb8dd617f4051f6cd
+ generation_id: 0dbe2079-841d-4be1-b585-ea25ed80cc51
+ pristine_commit_hash: 300b132576e6f9a25a70f86fdd969f8be8475df7
+ pristine_tree_hash: 17295cc446a504bd5904e7e5b7be8072ce716da5
features:
python:
acceptHeaders: 3.0.0
@@ -9100,8 +9100,8 @@ trackedFiles:
pristine_git_object: 62eedd2321693acb84070b67518bcf8746e71d25
docs/operations/createkeysrequestbody.mdx:
id: 77bb49febf62
- last_write_checksum: sha1:53ddb0480e248afc962772562a9fcd22482cd6bc
- pristine_git_object: 90aa2781dfc3d4bb722954277a376340f5d62fca
+ last_write_checksum: sha1:a4d813bf0eb6fbff50e00b9733e85253e14249f5
+ pristine_git_object: 3f35133302ca574bb5599060b040ff9829026ec8
docs/operations/createkeysresponse.mdx:
id: 08e825fab080
last_write_checksum: sha1:ad171dae3c841d8f21b63a8266c79f22b2d5310c
@@ -10180,8 +10180,8 @@ trackedFiles:
pristine_git_object: df35dcd1bd18f96a586f213c620bbb73197093bf
docs/operations/listrequest.mdx:
id: 2652e61cd671
- last_write_checksum: sha1:eafa93c306fc54d2547e11975bcfe939246041d6
- pristine_git_object: f8b721eb4e9888869e4e4fedde862c2702ab7f30
+ last_write_checksum: sha1:843417bf455bcfb50f582a7125f7cecd55da8b47
+ pristine_git_object: e0298f128f4fac5b60ecbd405fc4f251ed23c128
docs/operations/listresponse.mdx:
id: 0fbda0f81ae8
last_write_checksum: sha1:73963968eb448421e0ad3a5a442192da7c46c6a9
@@ -10616,8 +10616,8 @@ trackedFiles:
pristine_git_object: 2cfd14c40ab962877968c79c6c958ea432a4f083
docs/sdks/apikeys/README.mdx:
id: 27fcaae1c346
- last_write_checksum: sha1:6142567ac9c61aecbccc8e177cf5486b15fc26dd
- pristine_git_object: d6775ca68b50b946cdc33eee32588db60934fc43
+ last_write_checksum: sha1:84590ae50035abe2b53b292186cf494408af4030
+ pristine_git_object: 21c449e89a2a1c61383688877f836cb10d2efd2e
docs/sdks/batch/README.mdx:
id: e367aa4f4295
last_write_checksum: sha1:e5084fc19c2bfc9aa28e90a86d4accb5c9153130
@@ -10768,8 +10768,8 @@ trackedFiles:
pristine_git_object: 3e38f1a929f7d6b1d6de74604aa87e3d8f010544
pyproject.toml:
id: 5d07e7d72637
- last_write_checksum: sha1:80d96447577f36c39ac5a430102b74ec23bd727c
- pristine_git_object: 1d7d2dd2e33c2cc456254bd409c6602682a6b16c
+ last_write_checksum: sha1:54b99d324db9efe50e290ce6b0e3972bd9b19941
+ pristine_git_object: eee4fbe981c6a96891c2e9e85fe9cba2f3b26cd3
scripts/prepare_readme.py:
id: e0c5957a6035
last_write_checksum: sha1:77f44b60b98bc126557ec27391f91dfba764bb54
@@ -10796,8 +10796,8 @@ trackedFiles:
pristine_git_object: 86713cfea633e09d33b3d4e65281071fe20e6137
src/openrouter/_version.py:
id: d8d15ad6c586
- last_write_checksum: sha1:893c7d1fb3156ec74b7aaaeb8c3f79b7a4df9568
- pristine_git_object: 7c705ab99672990ae84fdafb09e65b2196e8bc4c
+ last_write_checksum: sha1:77a9090ce9a36b990370abbdffe21a2deac21d20
+ pristine_git_object: 82fd6be23091771ee11b1c8ee59edc48e404ecad
src/openrouter/alpha.py:
id: 306c4d93308d
last_write_checksum: sha1:80cc0f39649445431cc2247ed0e0765438467766
@@ -10808,8 +10808,8 @@ trackedFiles:
pristine_git_object: 0e567f3a37cc6aeb45a2551d0d500412e4b7796d
src/openrouter/api_keys.py:
id: 876fac88fff6
- last_write_checksum: sha1:d1f1037e108264d868284f3fd867e1f36739fca3
- pristine_git_object: 06c6ce3fcdca15b0c93eae9e7fc5594ab086749a
+ last_write_checksum: sha1:78bf0fcf8a3d194494c8f8d0c2f3f29c893c65b1
+ pristine_git_object: 837cbce7fcb6e2d62545b46c09a11cb291171a60
src/openrouter/basesdk.py:
id: c5733c5a1e12
last_write_checksum: sha1:65769ff2cb5473f85b364c6213a0ddc8c68644ea
@@ -14676,8 +14676,8 @@ trackedFiles:
pristine_git_object: 8216a656ec1412a034878e257bd9de9e94fa8da1
src/openrouter/operations/createkeys.py:
id: 64ad31fdaa6c
- last_write_checksum: sha1:eebe714328243c8e6e0235e561f45ad03a0048e1
- pristine_git_object: ce2e09a76c67cdd803e15ddd2a9189c31cbecc24
+ last_write_checksum: sha1:0f87b3e97a21a01c1c9b9da5f81c97677026d6e6
+ pristine_git_object: 778f557b94a841ad99c9326ddd8bcd98ed87029e
src/openrouter/operations/createoauthtoken.py:
id: 02e1c061780d
last_write_checksum: sha1:006884cfeeecfede1434f194460b7189cae89de1
@@ -14936,8 +14936,8 @@ trackedFiles:
pristine_git_object: 0365c6edd5a01c4086dfcf75d326fb48a67ad9d6
src/openrouter/operations/list.py:
id: 3ced31e3804e
- last_write_checksum: sha1:eee1e1075132399c1e45e6f5e0ad953cb6dea968
- pristine_git_object: 97ae1810d050828a392fca9f0368927728a4e2d4
+ last_write_checksum: sha1:ed6233bd58de02cb3126d333c2e361b83d8b5bce
+ pristine_git_object: bf7d30f58097da5c25d83a257163f280c7276693
src/openrouter/operations/listbatches.py:
id: 9ad1345dc956
last_write_checksum: sha1:b7017793a979647ef2ec7fee333e34063664c9eb
@@ -15652,6 +15652,8 @@ examples:
application/json: {"error": {"code": 400, "message": "Invalid request parameters"}}
"404":
application/json: {"error": {"code": 404, "message": "Resource not found"}}
+ "403":
+ application/json: {"error": {"code": 403, "message": "Only management keys can perform this operation"}}
createKeys:
speakeasy-default-create-keys:
requestBody:
@@ -15727,6 +15729,8 @@ examples:
application/json: {"error": {"code": 429, "message": "Rate limit exceeded"}}
"500":
application/json: {"error": {"code": 500, "message": "Internal Server Error"}}
+ "403":
+ application/json: {"error": {"code": 403, "message": "Only management keys can perform this operation"}}
getKey:
speakeasy-default-get-key:
parameters:
@@ -15743,6 +15747,8 @@ examples:
application/json: {"error": {"code": 429, "message": "Rate limit exceeded"}}
"500":
application/json: {"error": {"code": 500, "message": "Internal Server Error"}}
+ "403":
+ application/json: {"error": {"code": 403, "message": "Only management keys can perform this operation"}}
getCurrentKey:
speakeasy-default-get-current-key:
responses:
@@ -19874,4 +19880,6 @@ examples:
examplesVersion: 1.0.2
releaseNotes: |
## Python SDK Changes:
- * `open_router.endpoints.list_zdr_endpoints()`: `response.data[].safety_retention` **Added**
+ * `open_router.api_keys.list()`: `error.status[403]` **Added**
+ * `open_router.api_keys.delete()`: `error.status[403]` **Added**
+ * `open_router.api_keys.get()`: `error.status[403]` **Added**
diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml
index c7aee373..83ed7b1b 100644
--- a/.speakeasy/gen.yaml
+++ b/.speakeasy/gen.yaml
@@ -37,7 +37,7 @@ generation:
documentation: mintlify
preApplyUnionDiscriminators: true
python:
- version: 1.3.104
+ version: 1.3.105
additionalDependencies:
dev:
pytest: '>=8.3'
diff --git a/.speakeasy/out.openapi.yaml b/.speakeasy/out.openapi.yaml
index 95216b7b..cf68acfa 100644
--- a/.speakeasy/out.openapi.yaml
+++ b/.speakeasy/out.openapi.yaml
@@ -44837,12 +44837,12 @@ paths:
- 'integer'
- 'null'
nullable: false
- - description: 'Filter API keys by workspace ID. By default, keys in the default workspace are returned.'
+ - description: 'Filter API keys by workspace ID. By default an organization-scoped management key gets the default workspace; a workspace-scoped management key always gets its own workspace and cannot list another.'
in: 'query'
name: 'workspace_id'
required: false
schema:
- description: 'Filter API keys by workspace ID. By default, keys in the default workspace are returned.'
+ description: 'Filter API keys by workspace ID. By default an organization-scoped management key gets the default workspace; a workspace-scoped management key always gets its own workspace and cannot list another.'
example: '0df9e665-d932-5740-b2c7-b52af166bc11'
format: 'uuid'
type: 'string'
@@ -45098,6 +45098,16 @@ paths:
schema:
$ref: '#/components/schemas/UnauthorizedResponse'
description: 'Unauthorized - Authentication required or invalid credentials'
+ '403':
+ content:
+ application/json:
+ example:
+ error:
+ code: 403
+ message: 'Only management keys can perform this operation'
+ schema:
+ $ref: '#/components/schemas/ForbiddenResponse'
+ description: 'Forbidden - Authentication successful but insufficient permissions'
'404':
content:
application/json:
@@ -45215,7 +45225,7 @@ paths:
minLength: 1
type: 'string'
workspace_id:
- description: 'The workspace to create the API key in. Defaults to the default workspace if not provided.'
+ description: 'The workspace to create the API key in. Defaults to the default workspace for an organization-scoped management key, or to the management key''s own workspace for a workspace-scoped one, which cannot create keys elsewhere.'
example: '0df9e665-d932-5740-b2c7-b52af166bc11'
format: 'uuid'
type: 'string'
@@ -45561,6 +45571,16 @@ paths:
schema:
$ref: '#/components/schemas/UnauthorizedResponse'
description: 'Unauthorized - Authentication required or invalid credentials'
+ '403':
+ content:
+ application/json:
+ example:
+ error:
+ code: 403
+ message: 'Only management keys can perform this operation'
+ schema:
+ $ref: '#/components/schemas/ForbiddenResponse'
+ description: 'Forbidden - Authentication successful but insufficient permissions'
'404':
content:
application/json:
@@ -45847,6 +45867,16 @@ paths:
schema:
$ref: '#/components/schemas/UnauthorizedResponse'
description: 'Unauthorized - Authentication required or invalid credentials'
+ '403':
+ content:
+ application/json:
+ example:
+ error:
+ code: 403
+ message: 'Only management keys can perform this operation'
+ schema:
+ $ref: '#/components/schemas/ForbiddenResponse'
+ description: 'Forbidden - Authentication successful but insufficient permissions'
'404':
content:
application/json:
diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock
index a929f5df..5bd50e02 100644
--- a/.speakeasy/workflow.lock
+++ b/.speakeasy/workflow.lock
@@ -2,8 +2,8 @@ speakeasyVersion: 1.803.2
sources:
OpenRouter API:
sourceNamespace: open-router-chat-completions-api
- sourceRevisionDigest: sha256:f2ec7c45abce35a4ee889ecf63e1b7205c07047ad07a01b36cc700933c2f7738
- sourceBlobDigest: sha256:2e4abbb634949f2276fd2e3e2da11e201ba84a654602baf9c60002e28cc8f5f7
+ sourceRevisionDigest: sha256:6df88d5e094180489883aa48d0d4302a4345d6c8a5ff857760d1b3ee602d84f4
+ sourceBlobDigest: sha256:91a03aa9062657bb0682f562c7397d220e8ee8c2822f3304b4af404f0b15d9ff
tags:
- latest
- 1.0.0
@@ -11,10 +11,10 @@ targets:
open-router:
source: OpenRouter API
sourceNamespace: open-router-chat-completions-api
- sourceRevisionDigest: sha256:f2ec7c45abce35a4ee889ecf63e1b7205c07047ad07a01b36cc700933c2f7738
- sourceBlobDigest: sha256:2e4abbb634949f2276fd2e3e2da11e201ba84a654602baf9c60002e28cc8f5f7
+ sourceRevisionDigest: sha256:6df88d5e094180489883aa48d0d4302a4345d6c8a5ff857760d1b3ee602d84f4
+ sourceBlobDigest: sha256:91a03aa9062657bb0682f562c7397d220e8ee8c2822f3304b4af404f0b15d9ff
codeSamplesNamespace: open-router-python-code-samples
- codeSamplesRevisionDigest: sha256:3f4be72cb1b4642b401e6a72de66c4501e20d8b0880c1017f5825f9a033a58af
+ codeSamplesRevisionDigest: sha256:cb4d1dc79bddc7075ad1f64a84b0ba52631f172f63538939354591dde37614a6
workflow:
workflowVersion: 1.0.0
speakeasyVersion: 1.803.2
diff --git a/RELEASES.md b/RELEASES.md
index 45c4752f..5a55336a 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -3809,4 +3809,14 @@ Based on:
### Generated
- [python v1.3.104] .
### Releases
-- [PyPI v1.3.104] https://pypi.org/project/openrouter/1.3.104 - .
\ No newline at end of file
+- [PyPI v1.3.104] https://pypi.org/project/openrouter/1.3.104 - .
+
+## 2026-10-30 22:06:04
+### Changes
+Based on:
+- OpenAPI Doc
+- Speakeasy CLI 1.803.2 (2.950.13) https://github.com/speakeasy-api/speakeasy
+### Generated
+- [python v1.3.105] .
+### Releases
+- [PyPI v1.3.105] https://pypi.org/project/openrouter/1.3.105 - .
\ No newline at end of file
diff --git a/docs/operations/createkeysrequestbody.mdx b/docs/operations/createkeysrequestbody.mdx
index 90aa2781..3f351333 100644
--- a/docs/operations/createkeysrequestbody.mdx
+++ b/docs/operations/createkeysrequestbody.mdx
@@ -4,13 +4,13 @@ title: "CreateKeysRequestBody"
## Fields
-| Field | Type | Required | Description | Example |
-| --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `creator_user_id` | *OptionalNullable[str]* | ➖ | Optional user ID of the key creator. Only meaningful for organization-owned keys where a specific member is creating the key. | user_2dHFtVWx2n56w6HkM0000000000 |
-| `expires_at` | [date](https://docs.python.org/3/library/datetime.html#date-objects) | ➖ | Optional ISO 8601 UTC expiration timestamp. Must include seconds (YYYY-MM-DDTHH:MM:SSZ; fractional seconds allowed); minute-precision timestamps are rejected. | 2027-12-31T23:59:59Z |
-| `external` | [Optional[operations.External]](../operations/external.mdx) | ➖ | Optional partner-defined identity associated with the created API key. | |
-| `include_byok_in_limit` | *Optional[bool]* | ➖ | Whether to include BYOK usage in the limit | true |
-| `limit` | *OptionalNullable[float]* | ➖ | Optional spending limit for the API key in USD | 50 |
-| `limit_reset` | [OptionalNullable[operations.CreateKeysLimitReset]](../operations/createkeyslimitreset.mdx) | ➖ | Type of limit reset for the API key (daily, weekly, monthly, or null for no reset). Resets happen automatically at midnight UTC, and weeks are Monday through Sunday. | monthly |
-| `name` | *str* | ✔️ | Name for the new API key | My New API Key |
-| `workspace_id` | *Optional[str]* | ➖ | The workspace to create the API key in. Defaults to the default workspace if not provided. | 0df9e665-d932-5740-b2c7-b52af166bc11 |
\ No newline at end of file
+| Field | Type | Required | Description | Example |
+| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `creator_user_id` | *OptionalNullable[str]* | ➖ | Optional user ID of the key creator. Only meaningful for organization-owned keys where a specific member is creating the key. | user_2dHFtVWx2n56w6HkM0000000000 |
+| `expires_at` | [date](https://docs.python.org/3/library/datetime.html#date-objects) | ➖ | Optional ISO 8601 UTC expiration timestamp. Must include seconds (YYYY-MM-DDTHH:MM:SSZ; fractional seconds allowed); minute-precision timestamps are rejected. | 2027-12-31T23:59:59Z |
+| `external` | [Optional[operations.External]](../operations/external.mdx) | ➖ | Optional partner-defined identity associated with the created API key. | |
+| `include_byok_in_limit` | *Optional[bool]* | ➖ | Whether to include BYOK usage in the limit | true |
+| `limit` | *OptionalNullable[float]* | ➖ | Optional spending limit for the API key in USD | 50 |
+| `limit_reset` | [OptionalNullable[operations.CreateKeysLimitReset]](../operations/createkeyslimitreset.mdx) | ➖ | Type of limit reset for the API key (daily, weekly, monthly, or null for no reset). Resets happen automatically at midnight UTC, and weeks are Monday through Sunday. | monthly |
+| `name` | *str* | ✔️ | Name for the new API key | My New API Key |
+| `workspace_id` | *Optional[str]* | ➖ | The workspace to create the API key in. Defaults to the default workspace for an organization-scoped management key, or to the management key's own workspace for a workspace-scoped one, which cannot create keys elsewhere. | 0df9e665-d932-5740-b2c7-b52af166bc11 |
\ No newline at end of file
diff --git a/docs/operations/listrequest.mdx b/docs/operations/listrequest.mdx
index f8b721eb..e0298f12 100644
--- a/docs/operations/listrequest.mdx
+++ b/docs/operations/listrequest.mdx
@@ -4,12 +4,12 @@ title: "ListRequest"
## Fields
-| Field | Type | Required | Description | Example |
-| ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `http_referer` | *Optional[str]* | ➖ | The app identifier should be your app's URL and is used as the primary identifier for rankings.
This is used to track API usage per application.
| |
-| `x_open_router_title` | *Optional[str]* | ➖ | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| |
-| `x_open_router_categories` | *Optional[str]* | ➖ | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| |
-| `include_disabled` | *Optional[bool]* | ➖ | Whether to include disabled API keys in the response | false |
-| `include_expired` | *Optional[bool]* | ➖ | Whether to include expired API keys in the response. Expired keys are excluded by default and returned only when this is true. | false |
-| `offset` | *OptionalNullable[int]* | ➖ | Number of API keys to skip for pagination | 0 |
-| `workspace_id` | *Optional[str]* | ➖ | Filter API keys by workspace ID. By default, keys in the default workspace are returned. | 0df9e665-d932-5740-b2c7-b52af166bc11 |
\ No newline at end of file
+| Field | Type | Required | Description | Example |
+| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `http_referer` | *Optional[str]* | ➖ | The app identifier should be your app's URL and is used as the primary identifier for rankings.
This is used to track API usage per application.
| |
+| `x_open_router_title` | *Optional[str]* | ➖ | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| |
+| `x_open_router_categories` | *Optional[str]* | ➖ | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| |
+| `include_disabled` | *Optional[bool]* | ➖ | Whether to include disabled API keys in the response | false |
+| `include_expired` | *Optional[bool]* | ➖ | Whether to include expired API keys in the response. Expired keys are excluded by default and returned only when this is true. | false |
+| `offset` | *OptionalNullable[int]* | ➖ | Number of API keys to skip for pagination | 0 |
+| `workspace_id` | *Optional[str]* | ➖ | Filter API keys by workspace ID. By default an organization-scoped management key gets the default workspace; a workspace-scoped management key always gets its own workspace and cannot list another. | 0df9e665-d932-5740-b2c7-b52af166bc11 |
\ No newline at end of file
diff --git a/docs/sdks/apikeys/README.mdx b/docs/sdks/apikeys/README.mdx
index d6775ca6..21c449e8 100644
--- a/docs/sdks/apikeys/README.mdx
+++ b/docs/sdks/apikeys/README.mdx
@@ -89,16 +89,16 @@ with OpenRouter(
### Parameters
-| Parameter | Type | Required | Description | Example |
-| ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `http_referer` | *Optional[str]* | ➖ | The app identifier should be your app's URL and is used as the primary identifier for rankings.
This is used to track API usage per application.
| |
-| `x_open_router_title` | *Optional[str]* | ➖ | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| |
-| `x_open_router_categories` | *Optional[str]* | ➖ | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| |
-| `include_disabled` | *Optional[bool]* | ➖ | Whether to include disabled API keys in the response | false |
-| `include_expired` | *Optional[bool]* | ➖ | Whether to include expired API keys in the response. Expired keys are excluded by default and returned only when this is true. | false |
-| `offset` | *OptionalNullable[int]* | ➖ | Number of API keys to skip for pagination | 0 |
-| `workspace_id` | *Optional[str]* | ➖ | Filter API keys by workspace ID. By default, keys in the default workspace are returned. | 0df9e665-d932-5740-b2c7-b52af166bc11 |
-| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.mdx) | ➖ | Configuration to override the default retry behavior of the client. | |
+| Parameter | Type | Required | Description | Example |
+| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `http_referer` | *Optional[str]* | ➖ | The app identifier should be your app's URL and is used as the primary identifier for rankings.
This is used to track API usage per application.
| |
+| `x_open_router_title` | *Optional[str]* | ➖ | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| |
+| `x_open_router_categories` | *Optional[str]* | ➖ | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| |
+| `include_disabled` | *Optional[bool]* | ➖ | Whether to include disabled API keys in the response | false |
+| `include_expired` | *Optional[bool]* | ➖ | Whether to include expired API keys in the response. Expired keys are excluded by default and returned only when this is true. | false |
+| `offset` | *OptionalNullable[int]* | ➖ | Number of API keys to skip for pagination | 0 |
+| `workspace_id` | *Optional[str]* | ➖ | Filter API keys by workspace ID. By default an organization-scoped management key gets the default workspace; a workspace-scoped management key always gets its own workspace and cannot list another. | 0df9e665-d932-5740-b2c7-b52af166bc11 |
+| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.mdx) | ➖ | Configuration to override the default retry behavior of the client. | |
### Response
@@ -110,6 +110,7 @@ with OpenRouter(
| ----------------------------------- | ----------------------------------- | ----------------------------------- |
| errors.BadRequestResponseError | 400 | application/json |
| errors.UnauthorizedResponseError | 401 | application/json |
+| errors.ForbiddenResponseError | 403 | application/json |
| errors.NotFoundResponseError | 404 | application/json |
| errors.TooManyRequestsResponseError | 429 | application/json |
| errors.InternalServerResponseError | 500 | application/json |
@@ -143,20 +144,20 @@ with OpenRouter(
### Parameters
-| Parameter | Type | Required | Description | Example |
-| --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `name` | *str* | ✔️ | Name for the new API key | My New API Key |
-| `http_referer` | *Optional[str]* | ➖ | The app identifier should be your app's URL and is used as the primary identifier for rankings.
This is used to track API usage per application.
| |
-| `x_open_router_title` | *Optional[str]* | ➖ | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| |
-| `x_open_router_categories` | *Optional[str]* | ➖ | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| |
-| `creator_user_id` | *OptionalNullable[str]* | ➖ | Optional user ID of the key creator. Only meaningful for organization-owned keys where a specific member is creating the key. | user_2dHFtVWx2n56w6HkM0000000000 |
-| `expires_at` | [date](https://docs.python.org/3/library/datetime.html#date-objects) | ➖ | Optional ISO 8601 UTC expiration timestamp. Must include seconds (YYYY-MM-DDTHH:MM:SSZ; fractional seconds allowed); minute-precision timestamps are rejected. | 2027-12-31T23:59:59Z |
-| `external` | [Optional[operations.External]](../../operations/external.mdx) | ➖ | Optional partner-defined identity associated with the created API key. | |
-| `include_byok_in_limit` | *Optional[bool]* | ➖ | Whether to include BYOK usage in the limit | true |
-| `limit` | *OptionalNullable[float]* | ➖ | Optional spending limit for the API key in USD | 50 |
-| `limit_reset` | [OptionalNullable[operations.CreateKeysLimitReset]](../../operations/createkeyslimitreset.mdx) | ➖ | Type of limit reset for the API key (daily, weekly, monthly, or null for no reset). Resets happen automatically at midnight UTC, and weeks are Monday through Sunday. | monthly |
-| `workspace_id` | *Optional[str]* | ➖ | The workspace to create the API key in. Defaults to the default workspace if not provided. | 0df9e665-d932-5740-b2c7-b52af166bc11 |
-| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.mdx) | ➖ | Configuration to override the default retry behavior of the client. | |
+| Parameter | Type | Required | Description | Example |
+| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `name` | *str* | ✔️ | Name for the new API key | My New API Key |
+| `http_referer` | *Optional[str]* | ➖ | The app identifier should be your app's URL and is used as the primary identifier for rankings.
This is used to track API usage per application.
| |
+| `x_open_router_title` | *Optional[str]* | ➖ | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| |
+| `x_open_router_categories` | *Optional[str]* | ➖ | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| |
+| `creator_user_id` | *OptionalNullable[str]* | ➖ | Optional user ID of the key creator. Only meaningful for organization-owned keys where a specific member is creating the key. | user_2dHFtVWx2n56w6HkM0000000000 |
+| `expires_at` | [date](https://docs.python.org/3/library/datetime.html#date-objects) | ➖ | Optional ISO 8601 UTC expiration timestamp. Must include seconds (YYYY-MM-DDTHH:MM:SSZ; fractional seconds allowed); minute-precision timestamps are rejected. | 2027-12-31T23:59:59Z |
+| `external` | [Optional[operations.External]](../../operations/external.mdx) | ➖ | Optional partner-defined identity associated with the created API key. | |
+| `include_byok_in_limit` | *Optional[bool]* | ➖ | Whether to include BYOK usage in the limit | true |
+| `limit` | *OptionalNullable[float]* | ➖ | Optional spending limit for the API key in USD | 50 |
+| `limit_reset` | [OptionalNullable[operations.CreateKeysLimitReset]](../../operations/createkeyslimitreset.mdx) | ➖ | Type of limit reset for the API key (daily, weekly, monthly, or null for no reset). Resets happen automatically at midnight UTC, and weeks are Monday through Sunday. | monthly |
+| `workspace_id` | *Optional[str]* | ➖ | The workspace to create the API key in. Defaults to the default workspace for an organization-scoped management key, or to the management key's own workspace for a workspace-scoped one, which cannot create keys elsewhere. | 0df9e665-d932-5740-b2c7-b52af166bc11 |
+| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.mdx) | ➖ | Configuration to override the default retry behavior of the client. | |
### Response
@@ -217,6 +218,7 @@ with OpenRouter(
| Error Type | Status Code | Content Type |
| ----------------------------------- | ----------------------------------- | ----------------------------------- |
| errors.UnauthorizedResponseError | 401 | application/json |
+| errors.ForbiddenResponseError | 403 | application/json |
| errors.NotFoundResponseError | 404 | application/json |
| errors.TooManyRequestsResponseError | 429 | application/json |
| errors.InternalServerResponseError | 500 | application/json |
@@ -266,6 +268,7 @@ with OpenRouter(
| Error Type | Status Code | Content Type |
| ----------------------------------- | ----------------------------------- | ----------------------------------- |
| errors.UnauthorizedResponseError | 401 | application/json |
+| errors.ForbiddenResponseError | 403 | application/json |
| errors.NotFoundResponseError | 404 | application/json |
| errors.TooManyRequestsResponseError | 429 | application/json |
| errors.InternalServerResponseError | 500 | application/json |
diff --git a/pyproject.toml b/pyproject.toml
index 1d7d2dd2..eee4fbe9 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "openrouter"
-version = "1.3.104"
+version = "1.3.105"
description = "Official Python Client SDK for OpenRouter."
authors = [{ name = "OpenRouter" },]
readme = "README-PYPI.md"
diff --git a/src/openrouter/_version.py b/src/openrouter/_version.py
index 7c705ab9..82fd6be2 100644
--- a/src/openrouter/_version.py
+++ b/src/openrouter/_version.py
@@ -3,10 +3,10 @@
import importlib.metadata
__title__: str = "openrouter"
-__version__: str = "1.3.104"
+__version__: str = "1.3.105"
__openapi_doc_version__: str = "1.0.0"
__gen_version__: str = "2.950.13"
-__user_agent__: str = "speakeasy-sdk/python 1.3.104 2.950.13 1.0.0 openrouter"
+__user_agent__: str = "speakeasy-sdk/python 1.3.105 2.950.13 1.0.0 openrouter"
try:
if __package__ is not None:
diff --git a/src/openrouter/api_keys.py b/src/openrouter/api_keys.py
index 06c6ce3f..837cbce7 100644
--- a/src/openrouter/api_keys.py
+++ b/src/openrouter/api_keys.py
@@ -282,7 +282,7 @@ def list(
:param include_disabled: Whether to include disabled API keys in the response
:param include_expired: Whether to include expired API keys in the response. Expired keys are excluded by default and returned only when this is true.
:param offset: Number of API keys to skip for pagination
- :param workspace_id: Filter API keys by workspace ID. By default, keys in the default workspace are returned.
+ :param workspace_id: Filter API keys by workspace ID. By default an organization-scoped management key gets the default workspace; a workspace-scoped management key always gets its own workspace and cannot list another.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
:param timeout_ms: Override the default request timeout configuration for this method in milliseconds
@@ -372,6 +372,11 @@ def list(
errors.UnauthorizedResponseErrorData, http_res
)
raise errors.UnauthorizedResponseError(response_data, http_res)
+ if utils.match_response(http_res, "403", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.ForbiddenResponseErrorData, http_res
+ )
+ raise errors.ForbiddenResponseError(response_data, http_res)
if utils.match_response(http_res, "404", "application/json"):
response_data = unmarshal_json_response(
errors.NotFoundResponseErrorData, http_res
@@ -429,7 +434,7 @@ async def list_async(
:param include_disabled: Whether to include disabled API keys in the response
:param include_expired: Whether to include expired API keys in the response. Expired keys are excluded by default and returned only when this is true.
:param offset: Number of API keys to skip for pagination
- :param workspace_id: Filter API keys by workspace ID. By default, keys in the default workspace are returned.
+ :param workspace_id: Filter API keys by workspace ID. By default an organization-scoped management key gets the default workspace; a workspace-scoped management key always gets its own workspace and cannot list another.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
:param timeout_ms: Override the default request timeout configuration for this method in milliseconds
@@ -519,6 +524,11 @@ async def list_async(
errors.UnauthorizedResponseErrorData, http_res
)
raise errors.UnauthorizedResponseError(response_data, http_res)
+ if utils.match_response(http_res, "403", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.ForbiddenResponseErrorData, http_res
+ )
+ raise errors.ForbiddenResponseError(response_data, http_res)
if utils.match_response(http_res, "404", "application/json"):
response_data = unmarshal_json_response(
errors.NotFoundResponseErrorData, http_res
@@ -586,7 +596,7 @@ def create(
:param include_byok_in_limit: Whether to include BYOK usage in the limit
:param limit: Optional spending limit for the API key in USD
:param limit_reset: Type of limit reset for the API key (daily, weekly, monthly, or null for no reset). Resets happen automatically at midnight UTC, and weeks are Monday through Sunday.
- :param workspace_id: The workspace to create the API key in. Defaults to the default workspace if not provided.
+ :param workspace_id: The workspace to create the API key in. Defaults to the default workspace for an organization-scoped management key, or to the management key's own workspace for a workspace-scoped one, which cannot create keys elsewhere.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
:param timeout_ms: Override the default request timeout configuration for this method in milliseconds
@@ -758,7 +768,7 @@ async def create_async(
:param include_byok_in_limit: Whether to include BYOK usage in the limit
:param limit: Optional spending limit for the API key in USD
:param limit_reset: Type of limit reset for the API key (daily, weekly, monthly, or null for no reset). Resets happen automatically at midnight UTC, and weeks are Monday through Sunday.
- :param workspace_id: The workspace to create the API key in. Defaults to the default workspace if not provided.
+ :param workspace_id: The workspace to create the API key in. Defaults to the default workspace for an organization-scoped management key, or to the management key's own workspace for a workspace-scoped one, which cannot create keys elsewhere.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
:param timeout_ms: Override the default request timeout configuration for this method in milliseconds
@@ -996,6 +1006,11 @@ def delete(
errors.UnauthorizedResponseErrorData, http_res
)
raise errors.UnauthorizedResponseError(response_data, http_res)
+ if utils.match_response(http_res, "403", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.ForbiddenResponseErrorData, http_res
+ )
+ raise errors.ForbiddenResponseError(response_data, http_res)
if utils.match_response(http_res, "404", "application/json"):
response_data = unmarshal_json_response(
errors.NotFoundResponseErrorData, http_res
@@ -1129,6 +1144,11 @@ async def delete_async(
errors.UnauthorizedResponseErrorData, http_res
)
raise errors.UnauthorizedResponseError(response_data, http_res)
+ if utils.match_response(http_res, "403", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.ForbiddenResponseErrorData, http_res
+ )
+ raise errors.ForbiddenResponseError(response_data, http_res)
if utils.match_response(http_res, "404", "application/json"):
response_data = unmarshal_json_response(
errors.NotFoundResponseErrorData, http_res
@@ -1262,6 +1282,11 @@ def get(
errors.UnauthorizedResponseErrorData, http_res
)
raise errors.UnauthorizedResponseError(response_data, http_res)
+ if utils.match_response(http_res, "403", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.ForbiddenResponseErrorData, http_res
+ )
+ raise errors.ForbiddenResponseError(response_data, http_res)
if utils.match_response(http_res, "404", "application/json"):
response_data = unmarshal_json_response(
errors.NotFoundResponseErrorData, http_res
@@ -1395,6 +1420,11 @@ async def get_async(
errors.UnauthorizedResponseErrorData, http_res
)
raise errors.UnauthorizedResponseError(response_data, http_res)
+ if utils.match_response(http_res, "403", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.ForbiddenResponseErrorData, http_res
+ )
+ raise errors.ForbiddenResponseError(response_data, http_res)
if utils.match_response(http_res, "404", "application/json"):
response_data = unmarshal_json_response(
errors.NotFoundResponseErrorData, http_res
diff --git a/src/openrouter/operations/createkeys.py b/src/openrouter/operations/createkeys.py
index ce2e09a7..778f557b 100644
--- a/src/openrouter/operations/createkeys.py
+++ b/src/openrouter/operations/createkeys.py
@@ -143,7 +143,7 @@ class CreateKeysRequestBodyTypedDict(TypedDict):
limit_reset: NotRequired[Nullable[CreateKeysLimitReset]]
r"""Type of limit reset for the API key (daily, weekly, monthly, or null for no reset). Resets happen automatically at midnight UTC, and weeks are Monday through Sunday."""
workspace_id: NotRequired[str]
- r"""The workspace to create the API key in. Defaults to the default workspace if not provided."""
+ r"""The workspace to create the API key in. Defaults to the default workspace for an organization-scoped management key, or to the management key's own workspace for a workspace-scoped one, which cannot create keys elsewhere."""
class CreateKeysRequestBody(BaseModel):
@@ -169,7 +169,7 @@ class CreateKeysRequestBody(BaseModel):
r"""Type of limit reset for the API key (daily, weekly, monthly, or null for no reset). Resets happen automatically at midnight UTC, and weeks are Monday through Sunday."""
workspace_id: Optional[str] = None
- r"""The workspace to create the API key in. Defaults to the default workspace if not provided."""
+ r"""The workspace to create the API key in. Defaults to the default workspace for an organization-scoped management key, or to the management key's own workspace for a workspace-scoped one, which cannot create keys elsewhere."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
diff --git a/src/openrouter/operations/list.py b/src/openrouter/operations/list.py
index 97ae1810..bf7d30f5 100644
--- a/src/openrouter/operations/list.py
+++ b/src/openrouter/operations/list.py
@@ -101,7 +101,7 @@ class ListRequestTypedDict(TypedDict):
offset: NotRequired[Nullable[int]]
r"""Number of API keys to skip for pagination"""
workspace_id: NotRequired[str]
- r"""Filter API keys by workspace ID. By default, keys in the default workspace are returned."""
+ r"""Filter API keys by workspace ID. By default an organization-scoped management key gets the default workspace; a workspace-scoped management key always gets its own workspace and cannot list another."""
class ListRequest(BaseModel):
@@ -155,7 +155,7 @@ class ListRequest(BaseModel):
Optional[str],
FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
] = None
- r"""Filter API keys by workspace ID. By default, keys in the default workspace are returned."""
+ r"""Filter API keys by workspace ID. By default an organization-scoped management key gets the default workspace; a workspace-scoped management key always gets its own workspace and cannot list another."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
diff --git a/uv.lock b/uv.lock
index 4d199f01..f20764d5 100644
--- a/uv.lock
+++ b/uv.lock
@@ -231,7 +231,7 @@ wheels = [
[[package]]
name = "openrouter"
-version = "1.3.104"
+version = "1.3.105"
source = { editable = "." }
dependencies = [
{ name = "httpcore" },