diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock index 1e6bb715..2b29a829 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: 63ba3216b2499bb104f5ba497212cf31 + docChecksum: ecb5eca3ef6a267213db0ded757b55e3 docVersion: 1.0.0 speakeasyVersion: 1.787.0 generationVersion: 2.914.0 - releaseVersion: 1.3.39 - configChecksum: 087e7677c4446238e5e3330e10a2f485 + releaseVersion: 1.3.40 + configChecksum: ee9a5a783a8eacb732f771decfd8b7db repoURL: https://github.com/OpenRouterTeam/python-sdk.git installationURL: https://github.com/OpenRouterTeam/python-sdk.git published: true persistentEdits: - generation_id: 7bb99ffd-de0f-43a3-bedf-0b7ba639e3ee - pristine_commit_hash: a065177d322362e8b66a40bae6ae5286f280d0d7 - pristine_tree_hash: 59713b5944267b079a2cd2c4f9461d4d1e958909 + generation_id: 71c9c96b-57d8-43db-a7fd-358f31fd9922 + pristine_commit_hash: 56313cab4b918fcdba448e161f1d1440024301e6 + pristine_tree_hash: 6a298d935c5177a5636b85c8c413ee28b7dcbe89 features: python: acceptHeaders: 3.0.0 @@ -9796,8 +9796,8 @@ trackedFiles: pristine_git_object: e6d3d7f0130773c07971473e1bc4e536b403a993 docs/operations/updatekeysrequestbody.mdx: id: dc55066cca3d - last_write_checksum: sha1:28fd19213cd690e7aec9fa106db1b835094a9d3a - pristine_git_object: b293f36e7709b7bebad59271db0885d29711c2d9 + last_write_checksum: sha1:6a8c00577467c533b49ce9d0a4a1742993730034 + pristine_git_object: bc08a2d46ccca8a3a8d61d196611ecc7c0782903 docs/operations/updatekeysresponse.mdx: id: a97d51fea627 last_write_checksum: sha1:e3064726562fa278b17b113764602a46e0919ffe @@ -9920,8 +9920,8 @@ trackedFiles: pristine_git_object: c1634706646332455817340f5891b4b5c9c6d16c docs/sdks/apikeys/README.mdx: id: 27fcaae1c346 - last_write_checksum: sha1:dece70cc0e48aa3e8f523d4b27844e1f870d1b2d - pristine_git_object: 211cfc120a8941c8006179541b6ba9bb8599f661 + last_write_checksum: sha1:d904a5734d4cf752acf932c54fa8cb714034e38c + pristine_git_object: 558caa92f560fd87cb7ed6bb6d1989b7a5001c81 docs/sdks/batch/README.mdx: id: e367aa4f4295 last_write_checksum: sha1:03ef59395c1bc1a4ffa14dd68ca2a77a72601080 @@ -10068,8 +10068,8 @@ trackedFiles: pristine_git_object: 3e38f1a929f7d6b1d6de74604aa87e3d8f010544 pyproject.toml: id: 5d07e7d72637 - last_write_checksum: sha1:ae86206d341aa777b7b704f3b55146ddaa47ed1e - pristine_git_object: 603917d374eaecf1b6cf8f220f107be47c2d3793 + last_write_checksum: sha1:13e86e0bb1241458142202f2f8f09b882ed9eaef + pristine_git_object: 58dec50a7d7a3657ca82dc463ebe5868b50a680c scripts/prepare_readme.py: id: e0c5957a6035 last_write_checksum: sha1:77f44b60b98bc126557ec27391f91dfba764bb54 @@ -10096,8 +10096,8 @@ trackedFiles: pristine_git_object: 86713cfea633e09d33b3d4e65281071fe20e6137 src/openrouter/_version.py: id: d8d15ad6c586 - last_write_checksum: sha1:384892b86cee88cd2af1039fc03d15de610578af - pristine_git_object: 0cf6cc22eabc83b4cefb2d11d0a175413bbbed9d + last_write_checksum: sha1:c6901839a49042fdd00a20f0200548c0cd92d0a0 + pristine_git_object: b42d7fe103d72102be9150bae1c462b64e09d461 src/openrouter/alpha.py: id: 306c4d93308d last_write_checksum: sha1:30f55a360f41376ab194b9ea725fe4e001a5ae1a @@ -10108,8 +10108,8 @@ trackedFiles: pristine_git_object: 9587309db4d5e25a00131a48788456139c25e4c0 src/openrouter/api_keys.py: id: 876fac88fff6 - last_write_checksum: sha1:42bbc2aadb2722a96eba3c83eff26afcfa6a0572 - pristine_git_object: 1b9ba98c188a8887d8dd27bc9f200deaacdcdef6 + last_write_checksum: sha1:be6e31bd6aa3b8cacec826ba4b249739b4510b79 + pristine_git_object: 3c95e38bd085b026382bace5eab99a7cc91af00a src/openrouter/basesdk.py: id: c5733c5a1e12 last_write_checksum: sha1:65769ff2cb5473f85b364c6213a0ddc8c68644ea @@ -14288,8 +14288,8 @@ trackedFiles: pristine_git_object: d87519cfb18258224c2958076dedb16ff4abe208 src/openrouter/operations/updatekeys.py: id: 56fb213253a8 - last_write_checksum: sha1:d70e4b1e06f8b0e1569a172e263b3e541edf4442 - pristine_git_object: 3862d92575f681cc5eb43fd27d3d57114972ed2e + last_write_checksum: sha1:8a49a1d8fecd7314d177d488ecec30214f4e918b + pristine_git_object: e9ed9da08d2a39aa0f9dc295fdd4e006e8dd49f5 src/openrouter/operations/updateobservabilitydestination.py: id: 18e06708d1b4 last_write_checksum: sha1:d490e19e8698ed5193df9d06673f975cb3a1410f @@ -14807,6 +14807,10 @@ 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"}} + "409": + application/json: {"error": {"code": 409, "message": "Resource conflict. Please try again later."}} invalid_parameters: parameters: path: @@ -18432,3 +18436,4 @@ examples: "500": application/json: {"error": {"code": 404, "message": "Intern not found"}} examplesVersion: 1.0.2 +releaseNotes: "## Python SDK Changes:\n* `open_router.api_keys.update()`: \n * `request.workspace_id` **Added**\n * `error` **Changed**\n" diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml index f67817a7..c2d663d1 100644 --- a/.speakeasy/gen.yaml +++ b/.speakeasy/gen.yaml @@ -36,7 +36,7 @@ generation: documentation: mintlify preApplyUnionDiscriminators: true python: - version: 1.3.39 + version: 1.3.40 additionalDependencies: dev: {} main: {} diff --git a/.speakeasy/out.openapi.yaml b/.speakeasy/out.openapi.yaml index aa58935c..d32e9c3e 100644 --- a/.speakeasy/out.openapi.yaml +++ b/.speakeasy/out.openapi.yaml @@ -44741,7 +44741,7 @@ paths: - 'API Keys' x-speakeasy-name-override: 'get' patch: - description: "Update an existing API key. Authenticate with a [management key](/docs/guides/overview/auth/management-api-keys).\n\n\nYou can't change `workspace_id` through the API. The request body accepts only the fields listed below, and unrecognized fields are ignored. To move a key to another workspace, use the OpenRouter dashboard. If the body contains none of the accepted fields, the request fails with `400` and the message `No update fields provided`.\n" + description: "Update an existing API key. Authenticate with a [management key](/docs/guides/overview/auth/management-api-keys).\n\nSet `workspace_id` to move the key to another workspace. The key keeps its value, and any other fields in the same request are applied atomically with the move. Guardrail selections move with the key; other workspace-scoped settings (presets, BYOK keys, broadcast destinations, routing rules) do not. A move into or out of a HIPAA workspace is refused with `403`. In an organization, if the key's creator is not a member of a non-default target workspace, the request fails with `409`; add them to the workspace first.\n\n\nThe request body accepts only the fields listed below, and unrecognized fields are ignored. If the body contains none of the accepted fields, the request fails with `400` and the message `No update fields provided`.\n" operationId: 'updateKeys' parameters: - description: 'The hash identifier of the API key to update' @@ -44800,6 +44800,11 @@ paths: description: 'New name for the API key' example: 'Updated API Key Name' type: 'string' + workspace_id: + description: 'Move the API key to this workspace. The key keeps its value; guardrail selections move with it, while other workspace-scoped settings (presets, BYOK keys, broadcast destinations, routing rules) do not. Sending the key''s current workspace is a no-op.' + example: '0df9e665-d932-5740-b2c7-b52af166bc11' + format: 'uuid' + type: 'string' type: 'object' required: true responses: @@ -45043,7 +45048,7 @@ paths: code: 400 message: 'Invalid request parameters' no_update_fields: - description: 'Returned when the body contains none of the accepted fields, for example `{"workspace_id": "..."}`. `workspace_id` can''t be changed through the API.' + description: 'Returned when the body contains none of the accepted fields, for example `{"label": "..."}`.' summary: 'No accepted fields in the request body' value: error: @@ -45062,6 +45067,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: @@ -45072,6 +45087,16 @@ paths: schema: $ref: '#/components/schemas/NotFoundResponse' description: 'Not Found - Resource does not exist' + '409': + content: + application/json: + example: + error: + code: 409 + message: 'The API key creator is not a member of the target workspace. Add them to the workspace, then retry.' + schema: + $ref: '#/components/schemas/ConflictResponse' + description: 'Conflict - Resource conflict or concurrent modification' '429': content: application/json: diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock index c10869d1..ac8a9ac0 100644 --- a/.speakeasy/workflow.lock +++ b/.speakeasy/workflow.lock @@ -2,8 +2,8 @@ speakeasyVersion: 1.787.0 sources: OpenRouter API: sourceNamespace: open-router-chat-completions-api - sourceRevisionDigest: sha256:cf24edf70629b35aad73aef00830d7d2f92f5f199bd6540c50f4887f848a33da - sourceBlobDigest: sha256:8c7c009a8ce7e8466887920f6d8c5246378189395521adf6e1a0464a23cf2caa + sourceRevisionDigest: sha256:c597251b8315aeabdac8771a04fa223bbd27a7ee37c50e7865f78a63b009cd05 + sourceBlobDigest: sha256:63d088f642ae5691d24c0fa0dcd9028d0cd2860692265db7a882af65fa3785aa tags: - latest - 1.0.0 @@ -11,10 +11,10 @@ targets: open-router: source: OpenRouter API sourceNamespace: open-router-chat-completions-api - sourceRevisionDigest: sha256:cf24edf70629b35aad73aef00830d7d2f92f5f199bd6540c50f4887f848a33da - sourceBlobDigest: sha256:8c7c009a8ce7e8466887920f6d8c5246378189395521adf6e1a0464a23cf2caa + sourceRevisionDigest: sha256:c597251b8315aeabdac8771a04fa223bbd27a7ee37c50e7865f78a63b009cd05 + sourceBlobDigest: sha256:63d088f642ae5691d24c0fa0dcd9028d0cd2860692265db7a882af65fa3785aa codeSamplesNamespace: open-router-python-code-samples - codeSamplesRevisionDigest: sha256:e4432a5e58f6864b1422ab41cc380048fc21238fbad0baa17b07dd9d855bb8b7 + codeSamplesRevisionDigest: sha256:a730ae87d313ee35964df1065a504ce678766c22dbc3b1692054285f0d381138 workflow: workflowVersion: 1.0.0 speakeasyVersion: 1.787.0 diff --git a/RELEASES.md b/RELEASES.md index 7db2a78a..8d0bde99 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -3159,4 +3159,14 @@ Based on: ### Generated - [python v1.3.39] . ### Releases -- [PyPI v1.3.39] https://pypi.org/project/openrouter/1.3.39 - . \ No newline at end of file +- [PyPI v1.3.39] https://pypi.org/project/openrouter/1.3.39 - . + +## 2026-10-09 15:16:59 +### Changes +Based on: +- OpenAPI Doc +- Speakeasy CLI 1.787.0 (2.914.0) https://github.com/speakeasy-api/speakeasy +### Generated +- [python v1.3.40] . +### Releases +- [PyPI v1.3.40] https://pypi.org/project/openrouter/1.3.40 - . \ No newline at end of file diff --git a/docs/operations/updatekeysrequestbody.mdx b/docs/operations/updatekeysrequestbody.mdx index 5db1aef1..9cf47d24 100644 --- a/docs/operations/updatekeysrequestbody.mdx +++ b/docs/operations/updatekeysrequestbody.mdx @@ -4,10 +4,11 @@ title: "UpdateKeysRequestBody" ## Fields -| Field | Type | Required | Description | Example | -| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `disabled` | *Optional[bool]* | ➖ | Whether to disable the API key | false | -| `include_byok_in_limit` | *Optional[bool]* | ➖ | Whether to include BYOK usage in the limit | true | -| `limit` | *OptionalNullable[float]* | ➖ | New spending limit for the API key in USD | 75 | -| `limit_reset` | [OptionalNullable[operations.UpdateKeysLimitReset]](../operations/updatekeyslimitreset.mdx) | ➖ | New limit reset type for the API key (daily, weekly, monthly, or null for no reset). Resets happen automatically at midnight UTC, and weeks are Monday through Sunday. | daily | -| `name` | *Optional[str]* | ➖ | New name for the API key | Updated API Key Name | \ No newline at end of file +| Field | Type | Required | Description | Example | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `disabled` | *Optional[bool]* | ➖ | Whether to disable the API key | false | +| `include_byok_in_limit` | *Optional[bool]* | ➖ | Whether to include BYOK usage in the limit | true | +| `limit` | *OptionalNullable[float]* | ➖ | New spending limit for the API key in USD | 75 | +| `limit_reset` | [OptionalNullable[operations.UpdateKeysLimitReset]](../operations/updatekeyslimitreset.mdx) | ➖ | New limit reset type for the API key (daily, weekly, monthly, or null for no reset). Resets happen automatically at midnight UTC, and weeks are Monday through Sunday. | daily | +| `name` | *Optional[str]* | ➖ | New name for the API key | Updated API Key Name | +| `workspace_id` | *Optional[str]* | ➖ | Move the API key to this workspace. The key keeps its value; guardrail selections move with it, while other workspace-scoped settings (presets, BYOK keys, broadcast destinations, routing rules) do not. Sending the key's current workspace is a no-op. | 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 07e3ac57..fb9a4aa0 100644 --- a/docs/sdks/apikeys/README.mdx +++ b/docs/sdks/apikeys/README.mdx @@ -274,8 +274,10 @@ with OpenRouter( Update an existing API key. Authenticate with a [management key](/docs/guides/overview/auth/management-api-keys). +Set `workspace_id` to move the key to another workspace. The key keeps its value, and any other fields in the same request are applied atomically with the move. Guardrail selections move with the key; other workspace-scoped settings (presets, BYOK keys, broadcast destinations, routing rules) do not. A move into or out of a HIPAA workspace is refused with `403`. In an organization, if the key's creator is not a member of a non-default target workspace, the request fails with `409`; add them to the workspace first. + \ -You can't change `workspace_id` through the API. The request body accepts only the fields listed below, and unrecognized fields are ignored. To move a key to another workspace, use the OpenRouter dashboard. If the body contains none of the accepted fields, the request fails with `400` and the message `No update fields provided`. +The request body accepts only the fields listed below, and unrecognized fields are ignored. If the body contains none of the accepted fields, the request fails with `400` and the message `No update fields provided`. ### Example Usage: invalid_parameters @@ -321,18 +323,19 @@ with OpenRouter( ### Parameters -| Parameter | Type | Required | Description | Example | -| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `hash` | *str* | ✅ | The hash identifier of the API key to update | f01d52606dc8f0a8303a7b5cc3fa07109c2e346cec7c0a16b40de462992ce943 | -| `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.
| | -| `disabled` | *Optional[bool]* | ➖ | Whether to disable the API key | false | -| `include_byok_in_limit` | *Optional[bool]* | ➖ | Whether to include BYOK usage in the limit | true | -| `limit` | *OptionalNullable[float]* | ➖ | New spending limit for the API key in USD | 75 | -| `limit_reset` | [OptionalNullable[operations.UpdateKeysLimitReset]](../../operations/updatekeyslimitreset.mdx) | ➖ | New limit reset type for the API key (daily, weekly, monthly, or null for no reset). Resets happen automatically at midnight UTC, and weeks are Monday through Sunday. | daily | -| `name` | *Optional[str]* | ➖ | New name for the API key | Updated API Key Name | -| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.mdx) | ➖ | Configuration to override the default retry behavior of the client. | | +| Parameter | Type | Required | Description | Example | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `hash` | *str* | ✅ | The hash identifier of the API key to update | f01d52606dc8f0a8303a7b5cc3fa07109c2e346cec7c0a16b40de462992ce943 | +| `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.
| | +| `disabled` | *Optional[bool]* | ➖ | Whether to disable the API key | false | +| `include_byok_in_limit` | *Optional[bool]* | ➖ | Whether to include BYOK usage in the limit | true | +| `limit` | *OptionalNullable[float]* | ➖ | New spending limit for the API key in USD | 75 | +| `limit_reset` | [OptionalNullable[operations.UpdateKeysLimitReset]](../../operations/updatekeyslimitreset.mdx) | ➖ | New limit reset type for the API key (daily, weekly, monthly, or null for no reset). Resets happen automatically at midnight UTC, and weeks are Monday through Sunday. | daily | +| `name` | *Optional[str]* | ➖ | New name for the API key | Updated API Key Name | +| `workspace_id` | *Optional[str]* | ➖ | Move the API key to this workspace. The key keeps its value; guardrail selections move with it, while other workspace-scoped settings (presets, BYOK keys, broadcast destinations, routing rules) do not. Sending the key's current workspace is a no-op. | 0df9e665-d932-5740-b2c7-b52af166bc11 | +| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.mdx) | ➖ | Configuration to override the default retry behavior of the client. | | ### Response @@ -344,7 +347,9 @@ with OpenRouter( | ----------------------------------- | ----------------------------------- | ----------------------------------- | | errors.BadRequestResponseError | 400 | application/json | | errors.UnauthorizedResponseError | 401 | application/json | +| errors.ForbiddenResponseError | 403 | application/json | | errors.NotFoundResponseError | 404 | application/json | +| errors.ConflictResponseError | 409 | application/json | | errors.TooManyRequestsResponseError | 429 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 603917d3..58dec50a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openrouter" -version = "1.3.39" +version = "1.3.40" 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 0cf6cc22..b42d7fe1 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.39" +__version__: str = "1.3.40" __openapi_doc_version__: str = "1.0.0" __gen_version__: str = "2.914.0" -__user_agent__: str = "speakeasy-sdk/python 1.3.39 2.914.0 1.0.0 openrouter" +__user_agent__: str = "speakeasy-sdk/python 1.3.40 2.914.0 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 1b9ba98c..3c95e38b 100644 --- a/src/openrouter/api_keys.py +++ b/src/openrouter/api_keys.py @@ -1425,6 +1425,7 @@ def update( limit: OptionalNullable[float] = UNSET, limit_reset: OptionalNullable[operations.UpdateKeysLimitReset] = UNSET, name: Optional[str] = None, + workspace_id: Optional[str] = None, retries: OptionalNullable[utils.RetryConfig] = UNSET, server_url: Optional[str] = None, timeout_ms: Optional[int] = None, @@ -1434,8 +1435,10 @@ def update( Update an existing API key. Authenticate with a [management key](/docs/guides/overview/auth/management-api-keys). + Set `workspace_id` to move the key to another workspace. The key keeps its value, and any other fields in the same request are applied atomically with the move. Guardrail selections move with the key; other workspace-scoped settings (presets, BYOK keys, broadcast destinations, routing rules) do not. A move into or out of a HIPAA workspace is refused with `403`. In an organization, if the key's creator is not a member of a non-default target workspace, the request fails with `409`; add them to the workspace first. + - You can't change `workspace_id` through the API. The request body accepts only the fields listed below, and unrecognized fields are ignored. To move a key to another workspace, use the OpenRouter dashboard. If the body contains none of the accepted fields, the request fails with `400` and the message `No update fields provided`. + The request body accepts only the fields listed below, and unrecognized fields are ignored. If the body contains none of the accepted fields, the request fails with `400` and the message `No update fields provided`. :param hash: The hash identifier of the API key to update @@ -1451,6 +1454,7 @@ def update( :param limit: New spending limit for the API key in USD :param limit_reset: New limit reset type 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 name: New name for the API key + :param workspace_id: Move the API key to this workspace. The key keeps its value; guardrail selections move with it, while other workspace-scoped settings (presets, BYOK keys, broadcast destinations, routing rules) do not. Sending the key's current workspace is a no-op. :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 @@ -1477,6 +1481,7 @@ def update( limit=limit, limit_reset=limit_reset, name=name, + workspace_id=workspace_id, ), ) @@ -1551,11 +1556,21 @@ def update( 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 ) raise errors.NotFoundResponseError(response_data, http_res) + if utils.match_response(http_res, "409", "application/json"): + response_data = unmarshal_json_response( + errors.ConflictResponseErrorData, http_res + ) + raise errors.ConflictResponseError(response_data, http_res) if utils.match_response(http_res, "429", "application/json"): response_data = unmarshal_json_response( errors.TooManyRequestsResponseErrorData, http_res @@ -1591,6 +1606,7 @@ async def update_async( limit: OptionalNullable[float] = UNSET, limit_reset: OptionalNullable[operations.UpdateKeysLimitReset] = UNSET, name: Optional[str] = None, + workspace_id: Optional[str] = None, retries: OptionalNullable[utils.RetryConfig] = UNSET, server_url: Optional[str] = None, timeout_ms: Optional[int] = None, @@ -1600,8 +1616,10 @@ async def update_async( Update an existing API key. Authenticate with a [management key](/docs/guides/overview/auth/management-api-keys). + Set `workspace_id` to move the key to another workspace. The key keeps its value, and any other fields in the same request are applied atomically with the move. Guardrail selections move with the key; other workspace-scoped settings (presets, BYOK keys, broadcast destinations, routing rules) do not. A move into or out of a HIPAA workspace is refused with `403`. In an organization, if the key's creator is not a member of a non-default target workspace, the request fails with `409`; add them to the workspace first. + - You can't change `workspace_id` through the API. The request body accepts only the fields listed below, and unrecognized fields are ignored. To move a key to another workspace, use the OpenRouter dashboard. If the body contains none of the accepted fields, the request fails with `400` and the message `No update fields provided`. + The request body accepts only the fields listed below, and unrecognized fields are ignored. If the body contains none of the accepted fields, the request fails with `400` and the message `No update fields provided`. :param hash: The hash identifier of the API key to update @@ -1617,6 +1635,7 @@ async def update_async( :param limit: New spending limit for the API key in USD :param limit_reset: New limit reset type 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 name: New name for the API key + :param workspace_id: Move the API key to this workspace. The key keeps its value; guardrail selections move with it, while other workspace-scoped settings (presets, BYOK keys, broadcast destinations, routing rules) do not. Sending the key's current workspace is a no-op. :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 @@ -1643,6 +1662,7 @@ async def update_async( limit=limit, limit_reset=limit_reset, name=name, + workspace_id=workspace_id, ), ) @@ -1717,11 +1737,21 @@ async def update_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 ) raise errors.NotFoundResponseError(response_data, http_res) + if utils.match_response(http_res, "409", "application/json"): + response_data = unmarshal_json_response( + errors.ConflictResponseErrorData, http_res + ) + raise errors.ConflictResponseError(response_data, http_res) if utils.match_response(http_res, "429", "application/json"): response_data = unmarshal_json_response( errors.TooManyRequestsResponseErrorData, http_res diff --git a/src/openrouter/operations/updatekeys.py b/src/openrouter/operations/updatekeys.py index 3862d925..e9ed9da0 100644 --- a/src/openrouter/operations/updatekeys.py +++ b/src/openrouter/operations/updatekeys.py @@ -108,6 +108,8 @@ class UpdateKeysRequestBodyTypedDict(TypedDict): r"""New limit reset type for the API key (daily, weekly, monthly, or null for no reset). Resets happen automatically at midnight UTC, and weeks are Monday through Sunday.""" name: NotRequired[str] r"""New name for the API key""" + workspace_id: NotRequired[str] + r"""Move the API key to this workspace. The key keeps its value; guardrail selections move with it, while other workspace-scoped settings (presets, BYOK keys, broadcast destinations, routing rules) do not. Sending the key's current workspace is a no-op.""" class UpdateKeysRequestBody(BaseModel): @@ -126,10 +128,20 @@ class UpdateKeysRequestBody(BaseModel): name: Optional[str] = None r"""New name for the API key""" + workspace_id: Optional[str] = None + r"""Move the API key to this workspace. The key keeps its value; guardrail selections move with it, while other workspace-scoped settings (presets, BYOK keys, broadcast destinations, routing rules) do not. Sending the key's current workspace is a no-op.""" + @model_serializer(mode="wrap") def serialize_model(self, handler): optional_fields = set( - ["disabled", "include_byok_in_limit", "limit", "limit_reset", "name"] + [ + "disabled", + "include_byok_in_limit", + "limit", + "limit_reset", + "name", + "workspace_id", + ] ) nullable_fields = set(["limit", "limit_reset"]) serialized = handler(self) diff --git a/uv.lock b/uv.lock index aa7019ff..0cff5aa5 100644 --- a/uv.lock +++ b/uv.lock @@ -213,7 +213,7 @@ wheels = [ [[package]] name = "openrouter" -version = "1.3.39" +version = "1.3.40" source = { editable = "." } dependencies = [ { name = "httpcore" },