diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock index 0cd65693..c79024c7 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: 4bd025f53fc2580c1adab2dec1499dca + docChecksum: be7c11dcf47add5989f403c393b004f7 docVersion: 1.0.0 speakeasyVersion: 1.787.0 generationVersion: 2.914.0 - releaseVersion: 1.1.26 - configChecksum: 4df5753b337f38beefa79b8bfef8319b + releaseVersion: 1.1.27 + configChecksum: cd57c8a0de51b8a03c8b09310929f01e repoURL: https://github.com/OpenRouterTeam/python-sdk.git installationURL: https://github.com/OpenRouterTeam/python-sdk.git published: true persistentEdits: - generation_id: 59507816-56c7-4f0b-90d2-dc5e846961fc - pristine_commit_hash: 120785b8533df4719a69079a96abe7c26ee4cdc8 - pristine_tree_hash: 3ffd1100c8437295e3f7442d4ee25fecb720cf38 + generation_id: 2bd77237-503a-4a76-a70e-c30ff7216a4d + pristine_commit_hash: 29dd98cf236ec587c0af26a6ee59169e4e4e24be + pristine_tree_hash: 6d691315fc84cf5072331ad8a3b838389435d1b0 features: python: acceptHeaders: 3.0.0 @@ -2164,6 +2164,10 @@ trackedFiles: id: 59edec5c97d1 last_write_checksum: sha1:e60a199f393362e0182d4b5aa6218294e6c1af48 pristine_git_object: 3031bf1129e51ad652a31b7142154b49fcc4560f + docs/components/getworkspacebudgetresponse.mdx: + id: 9a7d2b80e512 + last_write_checksum: sha1:a299ce75f8736a4d572a06a48e54e00854a63f0b + pristine_git_object: 2974de1ffe849cdfc1720bb7e3431a89ac4c9b14 docs/components/getworkspaceresponse.mdx: id: c8d0c4683019 last_write_checksum: sha1:5d10c3c4510cdc869a740deee62c31e9d2b02cc9 @@ -6320,6 +6324,14 @@ trackedFiles: id: 751150df8456 last_write_checksum: sha1:dd91989f271487fe03882f979e24cbd19ef1d306 pristine_git_object: 1b1c087538b67ecc69a464735f5af7bfbf777c1e + docs/operations/getworkspacebudgetglobals.mdx: + id: 364bec52e3ae + last_write_checksum: sha1:48f79d1434f1ce76ff36d9f86f84771f61254b3c + pristine_git_object: 9aa76f556ce0cdac2fa0c3755f4da8b5fc2db3c1 + docs/operations/getworkspacebudgetrequest.mdx: + id: 55fa8569d4ab + last_write_checksum: sha1:1a609b03011bb7c2adadee5296b81d0594a786e9 + pristine_git_object: 1e5648b8df0a67d2fd9f7da643dacf63b87fcbfb docs/operations/getworkspaceglobals.mdx: id: 50abe112c1f4 last_write_checksum: sha1:c01276f8bf7cc4708cd3e6eeea83c4ac9d97ccf6 @@ -7066,16 +7078,16 @@ trackedFiles: pristine_git_object: f277730478c66312d0e4bbb21fae715a9fcf14b9 docs/sdks/workspaces/README.mdx: id: 0c75d023ef6b - last_write_checksum: sha1:f517770e2ba836c7a0f9238dd950829207c5b1ca - pristine_git_object: 8fc6605c4a67012d439d41aea244c29a333ba787 + last_write_checksum: sha1:7c5a7d137506704b9afa3d0b93323c0998df5cda + pristine_git_object: 9a25256ed9125277444c2d762415eab9a430f1c6 py.typed: id: 258c3ed47ae4 last_write_checksum: sha1:8efc425ffe830805ffcc0f3055871bdcdc542c60 pristine_git_object: 3e38f1a929f7d6b1d6de74604aa87e3d8f010544 pyproject.toml: id: 5d07e7d72637 - last_write_checksum: sha1:aa22090e0b0c3844eabb41d5c20ff9f2437a3565 - pristine_git_object: 21b18c4152e6a4ff00490287b5d5d878dda1f8a7 + last_write_checksum: sha1:a264d9007e08b3eae1c2386bafd532997cef58f4 + pristine_git_object: 7e513fdef9903e80c52e5722af29177e5be59a12 scripts/prepare_readme.py: id: e0c5957a6035 last_write_checksum: sha1:77f44b60b98bc126557ec27391f91dfba764bb54 @@ -7102,8 +7114,8 @@ trackedFiles: pristine_git_object: 86713cfea633e09d33b3d4e65281071fe20e6137 src/openrouter/_version.py: id: d8d15ad6c586 - last_write_checksum: sha1:27705f13028414481341cd7909e975d4a5b560f2 - pristine_git_object: e7538015b3cbee72d2f456e80b219849ddc5508e + last_write_checksum: sha1:d58a79dc88238c0e3e3fe18d9e4dc5a4f537f159 + pristine_git_object: ace1bde4d196b0fb748a67f2dd51ee2b17331927 src/openrouter/analytics.py: id: cb406b5aaabb last_write_checksum: sha1:3ea0f1c73fb9c101b7bc5719da4dd7bf62ff469a @@ -7146,8 +7158,8 @@ trackedFiles: pristine_git_object: ad3d247954547814054c01989a2dff3d12b3e4e1 src/openrouter/components/__init__.py: id: 81754e97b3f4 - last_write_checksum: sha1:b0e873a60c008b4ef8336c155354ee8805dcb76a - pristine_git_object: 5659a9d1b2a765d579e4b89a13f36163b355b97a + last_write_checksum: sha1:6c39e9051ff665be30ed2c1e7e7f64ed272a5622 + pristine_git_object: 2a8ad9e6785f77e990e9b1818d7d68eae15757ce src/openrouter/components/aabenchmarkentry.py: id: e2e0f0b48c82 last_write_checksum: sha1:fab4d9a24d2cea937bb749d46c5f83941e99d65c @@ -8104,6 +8116,10 @@ trackedFiles: id: f6dd9e0daa9e last_write_checksum: sha1:0b1ba09ad5da624c4fdbd1bff5d8919e55133cb9 pristine_git_object: cfca9a058673bf7db640c2cec6d8dfc4f87837bd + src/openrouter/components/getworkspacebudgetresponse.py: + id: 5ae557de0b72 + last_write_checksum: sha1:49ee6ebadd481997bf9285d709847e5db8c0911c + pristine_git_object: b013b7e50d1573b98fe3f4f2fb08c8494a3e449a src/openrouter/components/getworkspaceresponse.py: id: d993d0c4c3da last_write_checksum: sha1:918535730d1c352bcc8fd2342e1c4cea89bc357f @@ -9658,8 +9674,8 @@ trackedFiles: pristine_git_object: 0f62389a8410522fe76eed82c64227903a8605c5 src/openrouter/operations/__init__.py: id: 9afcea1e7161 - last_write_checksum: sha1:10813e43c7af4d49a27bc034ae9c898a347a883c - pristine_git_object: 633049645a506d455ecef8e65b8a42edaf36bf42 + last_write_checksum: sha1:7462feea63bad287e4382464c6a5bf24b401eaa2 + pristine_git_object: 37c3c8ce47455812f19b303f0b4d34738ee1237a src/openrouter/operations/bulkaddworkspacemembers.py: id: e0ed56117619 last_write_checksum: sha1:5c44eb0d40fdece3ac084615f6c6082be4cf1d5a @@ -9880,6 +9896,10 @@ trackedFiles: id: 2ead327ab15e last_write_checksum: sha1:3dff8a41dc00770f6233f94b8233655f8310bc49 pristine_git_object: 1075e4c49f582db35eb921aa25d2b2baeb803dd3 + src/openrouter/operations/getworkspacebudget.py: + id: 1873b593f56e + last_write_checksum: sha1:099b2e1c71882774ddd7a998bd47fafffcc3b483 + pristine_git_object: 54a57c8768e85a76803a6a4002c48a7040b11a85 src/openrouter/operations/list.py: id: 3ced31e3804e last_write_checksum: sha1:5db489d16b321c49808ca3da9100839a72903f67 @@ -10174,8 +10194,8 @@ trackedFiles: pristine_git_object: 6460765cd23146b66e8b3b85bafd83ccf18d21c6 src/openrouter/workspaces.py: id: cd6c533b1802 - last_write_checksum: sha1:2a0bb110a1b5b9e9fcbca3f46dd4451b3e861cd3 - pristine_git_object: 015ceeebf877ef713bc7257dd47d01ee2c4d144c + last_write_checksum: sha1:273ca910cf9ea52419cfc681410fbf00b47adbd8 + pristine_git_object: d302cb5a478a949511c6de8bbf4260a3d0cfd536 examples: createResponses: speakeasy-default-create-responses: @@ -11635,6 +11655,8 @@ examples: application/json: {"error": {"code": 404, "message": "Resource not found"}} "500": application/json: {"error": {"code": 500, "message": "Internal Server Error"}} + "400": + application/json: {"error": {"code": 400, "message": "Invalid request parameters"}} upsertWorkspaceBudget: speakeasy-default-upsert-workspace-budget: parameters: @@ -11865,9 +11887,25 @@ examples: application/json: {"error": {"code": 404, "message": "Resource not found"}} "500": application/json: {"error": {"code": 500, "message": "Internal Server Error"}} + getWorkspaceBudget: + speakeasy-default-get-workspace-budget: + parameters: + path: + id: "production" + interval: "monthly" + responses: + "200": + application/json: {"data": {"created_at": "2025-08-24T10:30:00Z", "id": "770e8400-e29b-41d4-a716-446655440000", "limit_usd": 100, "reset_interval": "monthly", "updated_at": "2025-08-24T15:45:00Z", "workspace_id": "550e8400-e29b-41d4-a716-446655440000"}} + "400": + application/json: {"error": {"code": 400, "message": "Invalid request parameters"}} + "401": + application/json: {"error": {"code": 401, "message": "Missing Authentication header"}} + "404": + application/json: {"error": {"code": 404, "message": "Resource not found"}} + "500": + application/json: {"error": {"code": 500, "message": "Internal Server Error"}} examplesVersion: 1.0.2 releaseNotes: | ## Python SDK Changes: - * `open_router.tts.create_speech()`: `request.input_references` **Added** - * `open_router.endpoints.list_zdr_endpoints()`: `response.data[].supports_voice_cloning` **Added** - * `open_router.endpoints.list()`: `response.data.endpoints[].supports_voice_cloning` **Added** + * `open_router.workspaces.get_budget()`: **Added** + * `open_router.workspaces.delete_budget()`: `error.status[400]` **Added** diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml index 6c24f901..a5f7dba1 100644 --- a/.speakeasy/gen.yaml +++ b/.speakeasy/gen.yaml @@ -36,7 +36,7 @@ generation: documentation: mintlify preApplyUnionDiscriminators: true python: - version: 1.1.26 + version: 1.1.27 additionalDependencies: dev: {} main: {} diff --git a/.speakeasy/out.openapi.yaml b/.speakeasy/out.openapi.yaml index ab6410d8..2f1ef8bd 100644 --- a/.speakeasy/out.openapi.yaml +++ b/.speakeasy/out.openapi.yaml @@ -9635,6 +9635,28 @@ components: required: - 'data' type: 'object' + GetWorkspaceBudgetResponse: + example: + data: + created_at: '2025-08-24T10:30:00Z' + id: '770e8400-e29b-41d4-a716-446655440000' + limit_usd: 100 + reset_interval: 'monthly' + updated_at: '2025-08-24T15:45:00Z' + workspace_id: '550e8400-e29b-41d4-a716-446655440000' + include_byok_in_budgets: true + properties: + data: + allOf: + - $ref: '#/components/schemas/WorkspaceBudget' + - description: 'The budget for the requested interval' + include_byok_in_budgets: + description: 'Whether BYOK (bring-your-own-key) spend is included when enforcing the workspace''s budgets. This is a workspace-wide setting that applies to all budget intervals (daily, weekly, monthly, and lifetime).' + example: true + type: 'boolean' + required: + - 'data' + type: 'object' GetWorkspaceResponse: example: data: @@ -37462,6 +37484,16 @@ paths: schema: $ref: '#/components/schemas/DeleteWorkspaceBudgetResponse' description: 'Budget deleted successfully' + '400': + content: + application/json: + example: + error: + code: 400 + message: 'Invalid request parameters' + schema: + $ref: '#/components/schemas/BadRequestResponse' + description: 'Bad Request - Invalid request parameters or malformed input' '401': content: application/json: @@ -37496,6 +37528,86 @@ paths: tags: - 'Workspaces' x-speakeasy-name-override: 'deleteBudget' + get: + description: 'Retrieve the budget for a given interval. [Management key](/docs/guides/overview/auth/management-api-keys) required.' + operationId: 'getWorkspaceBudget' + parameters: + - description: 'The workspace ID (UUID) or slug' + in: 'path' + name: 'id' + required: true + schema: + description: 'The workspace ID (UUID) or slug' + example: 'production' + minLength: 1 + type: 'string' + - description: 'Budget reset interval. Use "lifetime" for a one-time budget that never resets.' + example: 'monthly' + in: 'path' + name: 'interval' + required: true + schema: + $ref: '#/components/schemas/WorkspaceBudgetInterval' + responses: + '200': + content: + application/json: + example: + data: + created_at: '2025-08-24T10:30:00Z' + id: '770e8400-e29b-41d4-a716-446655440000' + limit_usd: 100 + reset_interval: 'monthly' + updated_at: '2025-08-24T15:45:00Z' + workspace_id: '550e8400-e29b-41d4-a716-446655440000' + include_byok_in_budgets: true + schema: + $ref: '#/components/schemas/GetWorkspaceBudgetResponse' + description: 'Budget retrieved successfully' + '400': + content: + application/json: + example: + error: + code: 400 + message: 'Invalid request parameters' + schema: + $ref: '#/components/schemas/BadRequestResponse' + description: 'Bad Request - Invalid request parameters or malformed input' + '401': + content: + application/json: + example: + error: + code: 401 + message: 'Missing Authentication header' + schema: + $ref: '#/components/schemas/UnauthorizedResponse' + description: 'Unauthorized - Authentication required or invalid credentials' + '404': + content: + application/json: + example: + error: + code: 404 + message: 'Resource not found' + schema: + $ref: '#/components/schemas/NotFoundResponse' + description: 'Not Found - Resource does not exist' + '500': + content: + application/json: + example: + error: + code: 500 + message: 'Internal Server Error' + schema: + $ref: '#/components/schemas/InternalServerResponse' + description: 'Internal Server Error - Unexpected server error' + summary: 'Get a workspace budget' + tags: + - 'Workspaces' + x-speakeasy-name-override: 'getBudget' put: description: 'Create or update the budget for a given interval. Budget limits must strictly decrease as the interval narrows (lifetime > monthly > weekly > daily). The optional `include_byok_in_budgets` flag is a workspace-wide setting: when provided it applies to every budget interval for the workspace, not just the interval in this request. Note that a change made here is applied to budget enforcement immediately, but an already-open workspace settings page in the web dashboard may keep showing the previous value until it is reloaded. [Management key](/docs/guides/overview/auth/management-api-keys) required.' operationId: 'upsertWorkspaceBudget' diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock index dd1f2696..fbb5cbdc 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:f1344cdf479044bc22ce6c0e6b8d5e967069bce83ca7dd363b54c28cd148fb95 - sourceBlobDigest: sha256:9631f74074cfdeca4f58e1f195991bccbf8053252aada6bdbdd29baa8217ff08 + sourceRevisionDigest: sha256:f89a07d7220907360b9ac5ecea709b3307e39d9ab5bf499fe78541628d17f37c + sourceBlobDigest: sha256:439eb2fb58b83d4959ec1bddce024c1a426f31d3b6d21f130383a9c6d611b17f tags: - latest - 1.0.0 @@ -11,10 +11,10 @@ targets: open-router: source: OpenRouter API sourceNamespace: open-router-chat-completions-api - sourceRevisionDigest: sha256:f1344cdf479044bc22ce6c0e6b8d5e967069bce83ca7dd363b54c28cd148fb95 - sourceBlobDigest: sha256:9631f74074cfdeca4f58e1f195991bccbf8053252aada6bdbdd29baa8217ff08 + sourceRevisionDigest: sha256:f89a07d7220907360b9ac5ecea709b3307e39d9ab5bf499fe78541628d17f37c + sourceBlobDigest: sha256:439eb2fb58b83d4959ec1bddce024c1a426f31d3b6d21f130383a9c6d611b17f codeSamplesNamespace: open-router-python-code-samples - codeSamplesRevisionDigest: sha256:7ab6893fadfccf77a50b9b75a78da89433261a20515c86ac3daa2cdd75e78cda + codeSamplesRevisionDigest: sha256:5e817705b5cab5aa1a246b2d529ca39c280a66a80484e15a8e9708faf9190f89 workflow: workflowVersion: 1.0.0 speakeasyVersion: 1.787.0 diff --git a/RELEASES.md b/RELEASES.md index 8968f184..25db371f 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1049,4 +1049,14 @@ Based on: ### Generated - [python v1.1.26] . ### Releases -- [PyPI v1.1.26] https://pypi.org/project/openrouter/1.1.26 - . \ No newline at end of file +- [PyPI v1.1.26] https://pypi.org/project/openrouter/1.1.26 - . + +## 2026-08-04 06:55:49 +### Changes +Based on: +- OpenAPI Doc +- Speakeasy CLI 1.787.0 (2.914.0) https://github.com/speakeasy-api/speakeasy +### Generated +- [python v1.1.27] . +### Releases +- [PyPI v1.1.27] https://pypi.org/project/openrouter/1.1.27 - . \ No newline at end of file diff --git a/docs/components/getworkspacebudgetresponse.mdx b/docs/components/getworkspacebudgetresponse.mdx new file mode 100644 index 00000000..2974de1f --- /dev/null +++ b/docs/components/getworkspacebudgetresponse.mdx @@ -0,0 +1,10 @@ +--- +title: "GetWorkspaceBudgetResponse" +--- + +## Fields + +| Field | Type | Required | Description | Example | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `data` | [components.WorkspaceBudget](../components/workspacebudget.mdx) | :heavy_check_mark: | N/A | \{
"created_at": "2025-08-24T10:30:00Z",
"id": "770e8400-e29b-41d4-a716-446655440000",
"limit_usd": 100,
"reset_interval": "monthly",
"updated_at": "2025-08-24T15:45:00Z",
"workspace_id": "550e8400-e29b-41d4-a716-446655440000"
} | +| `include_byok_in_budgets` | *Optional[bool]* | :heavy_minus_sign: | Whether BYOK (bring-your-own-key) spend is included when enforcing the workspace's budgets. This is a workspace-wide setting that applies to all budget intervals (daily, weekly, monthly, and lifetime). | true | \ No newline at end of file diff --git a/docs/operations/getworkspacebudgetglobals.mdx b/docs/operations/getworkspacebudgetglobals.mdx new file mode 100644 index 00000000..9aa76f55 --- /dev/null +++ b/docs/operations/getworkspacebudgetglobals.mdx @@ -0,0 +1,11 @@ +--- +title: "GetWorkspaceBudgetGlobals" +--- + +## Fields + +| Field | Type | Required | Description | +| ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| `http_referer` | *Optional[str]* | :heavy_minus_sign: | 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]* | :heavy_minus_sign: | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| +| `x_open_router_categories` | *Optional[str]* | :heavy_minus_sign: | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| \ No newline at end of file diff --git a/docs/operations/getworkspacebudgetrequest.mdx b/docs/operations/getworkspacebudgetrequest.mdx new file mode 100644 index 00000000..1e5648b8 --- /dev/null +++ b/docs/operations/getworkspacebudgetrequest.mdx @@ -0,0 +1,13 @@ +--- +title: "GetWorkspaceBudgetRequest" +--- + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| `http_referer` | *Optional[str]* | :heavy_minus_sign: | 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]* | :heavy_minus_sign: | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| | +| `x_open_router_categories` | *Optional[str]* | :heavy_minus_sign: | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| | +| `id` | *str* | :heavy_check_mark: | The workspace ID (UUID) or slug | production | +| `interval` | [components.WorkspaceBudgetInterval](../components/workspacebudgetinterval.mdx) | :heavy_check_mark: | Budget reset interval. Use "lifetime" for a one-time budget that never resets. | monthly | \ No newline at end of file diff --git a/docs/sdks/workspaces/README.mdx b/docs/sdks/workspaces/README.mdx index 8fc6605c..9a25256e 100644 --- a/docs/sdks/workspaces/README.mdx +++ b/docs/sdks/workspaces/README.mdx @@ -16,6 +16,7 @@ Workspaces endpoints * [update](#update) - Update a workspace * [list_budgets](#list_budgets) - List workspace budgets * [delete_budget](#delete_budget) - Delete a workspace budget +* [get_budget](#get_budget) - Get a workspace budget * [set_budget](#set_budget) - Create or update a workspace budget * [list_members](#list_members) - List workspace members * [bulk_add_members](#bulk_add_members) - Bulk add members to a workspace @@ -381,6 +382,57 @@ with OpenRouter( | Error Type | Status Code | Content Type | | ---------------------------------- | ---------------------------------- | ---------------------------------- | +| errors.BadRequestResponseError | 400 | application/json | +| errors.UnauthorizedResponseError | 401 | application/json | +| errors.NotFoundResponseError | 404 | application/json | +| errors.InternalServerResponseError | 500 | application/json | +| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | + +## get_budget + +Retrieve the budget for a given interval. [Management key](/docs/guides/overview/auth/management-api-keys) required. + +### Example Usage + +```python +from openrouter import OpenRouter +import os + + +with OpenRouter( + http_referer="", + x_open_router_title="", + x_open_router_categories="", + api_key=os.getenv("OPENROUTER_API_KEY", ""), +) as open_router: + + res = open_router.workspaces.get_budget(id="production", interval="monthly") + + # Handle response + print(res) + +``` + +### Parameters + +| Parameter | Type | Required | Description | Example | +| ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| `id` | *str* | :heavy_check_mark: | The workspace ID (UUID) or slug | production | +| `interval` | [components.WorkspaceBudgetInterval](../../components/workspacebudgetinterval.mdx) | :heavy_check_mark: | Budget reset interval. Use "lifetime" for a one-time budget that never resets. | monthly | +| `http_referer` | *Optional[str]* | :heavy_minus_sign: | 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]* | :heavy_minus_sign: | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| | +| `x_open_router_categories` | *Optional[str]* | :heavy_minus_sign: | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| | +| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.mdx) | :heavy_minus_sign: | Configuration to override the default retry behavior of the client. | | + +### Response + +**[components.GetWorkspaceBudgetResponse](../../components/getworkspacebudgetresponse.mdx)** + +### Errors + +| Error Type | Status Code | Content Type | +| ---------------------------------- | ---------------------------------- | ---------------------------------- | +| errors.BadRequestResponseError | 400 | application/json | | errors.UnauthorizedResponseError | 401 | application/json | | errors.NotFoundResponseError | 404 | application/json | | errors.InternalServerResponseError | 500 | application/json | diff --git a/pyproject.toml b/pyproject.toml index 21b18c41..7e513fde 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openrouter" -version = "1.1.26" +version = "1.1.27" 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 e7538015..ace1bde4 100644 --- a/src/openrouter/_version.py +++ b/src/openrouter/_version.py @@ -3,10 +3,10 @@ import importlib.metadata __title__: str = "openrouter" -__version__: str = "1.1.26" +__version__: str = "1.1.27" __openapi_doc_version__: str = "1.0.0" __gen_version__: str = "2.914.0" -__user_agent__: str = "speakeasy-sdk/python 1.1.26 2.914.0 1.0.0 openrouter" +__user_agent__: str = "speakeasy-sdk/python 1.1.27 2.914.0 1.0.0 openrouter" try: if __package__ is not None: diff --git a/src/openrouter/components/__init__.py b/src/openrouter/components/__init__.py index 5659a9d1..2a8ad9e6 100644 --- a/src/openrouter/components/__init__.py +++ b/src/openrouter/components/__init__.py @@ -1181,6 +1181,10 @@ GetScimGroupMappingResponse, GetScimGroupMappingResponseTypedDict, ) + from .getworkspacebudgetresponse import ( + GetWorkspaceBudgetResponse, + GetWorkspaceBudgetResponseTypedDict, + ) from .getworkspaceresponse import ( GetWorkspaceResponse, GetWorkspaceResponseTypedDict, @@ -3866,6 +3870,8 @@ "GetPresetVersionResponseTypedDict", "GetScimGroupMappingResponse", "GetScimGroupMappingResponseTypedDict", + "GetWorkspaceBudgetResponse", + "GetWorkspaceBudgetResponseTypedDict", "GetWorkspaceResponse", "GetWorkspaceResponseTypedDict", "Guardrail", @@ -6067,6 +6073,8 @@ "GetPresetVersionResponseTypedDict": ".getpresetversionresponse", "GetScimGroupMappingResponse": ".getscimgroupmappingresponse", "GetScimGroupMappingResponseTypedDict": ".getscimgroupmappingresponse", + "GetWorkspaceBudgetResponse": ".getworkspacebudgetresponse", + "GetWorkspaceBudgetResponseTypedDict": ".getworkspacebudgetresponse", "GetWorkspaceResponse": ".getworkspaceresponse", "GetWorkspaceResponseTypedDict": ".getworkspaceresponse", "Guardrail": ".guardrail", diff --git a/src/openrouter/components/getworkspacebudgetresponse.py b/src/openrouter/components/getworkspacebudgetresponse.py new file mode 100644 index 00000000..b013b7e5 --- /dev/null +++ b/src/openrouter/components/getworkspacebudgetresponse.py @@ -0,0 +1,37 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +from __future__ import annotations +from .workspacebudget import WorkspaceBudget, WorkspaceBudgetTypedDict +from openrouter.types import BaseModel, UNSET_SENTINEL +from pydantic import model_serializer +from typing import Optional +from typing_extensions import NotRequired, TypedDict + + +class GetWorkspaceBudgetResponseTypedDict(TypedDict): + data: WorkspaceBudgetTypedDict + include_byok_in_budgets: NotRequired[bool] + r"""Whether BYOK (bring-your-own-key) spend is included when enforcing the workspace's budgets. This is a workspace-wide setting that applies to all budget intervals (daily, weekly, monthly, and lifetime).""" + + +class GetWorkspaceBudgetResponse(BaseModel): + data: WorkspaceBudget + + include_byok_in_budgets: Optional[bool] = None + r"""Whether BYOK (bring-your-own-key) spend is included when enforcing the workspace's budgets. This is a workspace-wide setting that applies to all budget intervals (daily, weekly, monthly, and lifetime).""" + + @model_serializer(mode="wrap") + def serialize_model(self, handler): + optional_fields = set(["include_byok_in_budgets"]) + serialized = handler(self) + m = {} + + for n, f in type(self).model_fields.items(): + k = f.alias or n + val = serialized.get(k, serialized.get(n)) + + if val != UNSET_SENTINEL: + if val is not None or k not in optional_fields: + m[k] = val + + return m diff --git a/src/openrouter/operations/__init__.py b/src/openrouter/operations/__init__.py index 63304964..37c3c8ce 100644 --- a/src/openrouter/operations/__init__.py +++ b/src/openrouter/operations/__init__.py @@ -469,6 +469,12 @@ GetWorkspaceRequest, GetWorkspaceRequestTypedDict, ) + from .getworkspacebudget import ( + GetWorkspaceBudgetGlobals, + GetWorkspaceBudgetGlobalsTypedDict, + GetWorkspaceBudgetRequest, + GetWorkspaceBudgetRequestTypedDict, + ) from .list import ( ListData, ListDataTypedDict, @@ -1127,6 +1133,10 @@ "GetVideosGlobalsTypedDict", "GetVideosRequest", "GetVideosRequestTypedDict", + "GetWorkspaceBudgetGlobals", + "GetWorkspaceBudgetGlobalsTypedDict", + "GetWorkspaceBudgetRequest", + "GetWorkspaceBudgetRequestTypedDict", "GetWorkspaceGlobals", "GetWorkspaceGlobalsTypedDict", "GetWorkspaceRequest", @@ -1774,6 +1784,10 @@ "GetWorkspaceGlobalsTypedDict": ".getworkspace", "GetWorkspaceRequest": ".getworkspace", "GetWorkspaceRequestTypedDict": ".getworkspace", + "GetWorkspaceBudgetGlobals": ".getworkspacebudget", + "GetWorkspaceBudgetGlobalsTypedDict": ".getworkspacebudget", + "GetWorkspaceBudgetRequest": ".getworkspacebudget", + "GetWorkspaceBudgetRequestTypedDict": ".getworkspacebudget", "ListData": ".list", "ListDataTypedDict": ".list", "ListGlobals": ".list", diff --git a/src/openrouter/operations/getworkspacebudget.py b/src/openrouter/operations/getworkspacebudget.py new file mode 100644 index 00000000..54a57c87 --- /dev/null +++ b/src/openrouter/operations/getworkspacebudget.py @@ -0,0 +1,155 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +from __future__ import annotations +from openrouter.components import ( + workspacebudgetinterval as components_workspacebudgetinterval, +) +from openrouter.types import BaseModel, UNSET_SENTINEL +from openrouter.utils import FieldMetadata, HeaderMetadata, PathParamMetadata +import pydantic +from pydantic import model_serializer +from typing import Optional +from typing_extensions import Annotated, NotRequired, TypedDict + + +class GetWorkspaceBudgetGlobalsTypedDict(TypedDict): + http_referer: NotRequired[str] + r"""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: NotRequired[str] + r"""The app display name allows you to customize how your app appears in OpenRouter's dashboard. + + """ + x_open_router_categories: NotRequired[str] + r"""Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings. + + """ + + +class GetWorkspaceBudgetGlobals(BaseModel): + http_referer: Annotated[ + Optional[str], + pydantic.Field(alias="HTTP-Referer"), + FieldMetadata(header=HeaderMetadata(style="simple", explode=False)), + ] = None + r"""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: Annotated[ + Optional[str], + pydantic.Field(alias="X-OpenRouter-Title"), + FieldMetadata(header=HeaderMetadata(style="simple", explode=False)), + ] = None + r"""The app display name allows you to customize how your app appears in OpenRouter's dashboard. + + """ + + x_open_router_categories: Annotated[ + Optional[str], + pydantic.Field(alias="X-OpenRouter-Categories"), + FieldMetadata(header=HeaderMetadata(style="simple", explode=False)), + ] = None + r"""Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings. + + """ + + @model_serializer(mode="wrap") + def serialize_model(self, handler): + optional_fields = set( + ["HTTP-Referer", "X-OpenRouter-Title", "X-OpenRouter-Categories"] + ) + serialized = handler(self) + m = {} + + for n, f in type(self).model_fields.items(): + k = f.alias or n + val = serialized.get(k, serialized.get(n)) + + if val != UNSET_SENTINEL: + if val is not None or k not in optional_fields: + m[k] = val + + return m + + +class GetWorkspaceBudgetRequestTypedDict(TypedDict): + id: str + r"""The workspace ID (UUID) or slug""" + interval: components_workspacebudgetinterval.WorkspaceBudgetInterval + r"""Budget reset interval. Use \"lifetime\" for a one-time budget that never resets.""" + http_referer: NotRequired[str] + r"""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: NotRequired[str] + r"""The app display name allows you to customize how your app appears in OpenRouter's dashboard. + + """ + x_open_router_categories: NotRequired[str] + r"""Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings. + + """ + + +class GetWorkspaceBudgetRequest(BaseModel): + id: Annotated[ + str, FieldMetadata(path=PathParamMetadata(style="simple", explode=False)) + ] + r"""The workspace ID (UUID) or slug""" + + interval: Annotated[ + components_workspacebudgetinterval.WorkspaceBudgetInterval, + FieldMetadata(path=PathParamMetadata(style="simple", explode=False)), + ] + r"""Budget reset interval. Use \"lifetime\" for a one-time budget that never resets.""" + + http_referer: Annotated[ + Optional[str], + pydantic.Field(alias="HTTP-Referer"), + FieldMetadata(header=HeaderMetadata(style="simple", explode=False)), + ] = None + r"""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: Annotated[ + Optional[str], + pydantic.Field(alias="X-OpenRouter-Title"), + FieldMetadata(header=HeaderMetadata(style="simple", explode=False)), + ] = None + r"""The app display name allows you to customize how your app appears in OpenRouter's dashboard. + + """ + + x_open_router_categories: Annotated[ + Optional[str], + pydantic.Field(alias="X-OpenRouter-Categories"), + FieldMetadata(header=HeaderMetadata(style="simple", explode=False)), + ] = None + r"""Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings. + + """ + + @model_serializer(mode="wrap") + def serialize_model(self, handler): + optional_fields = set( + ["HTTP-Referer", "X-OpenRouter-Title", "X-OpenRouter-Categories"] + ) + serialized = handler(self) + m = {} + + for n, f in type(self).model_fields.items(): + k = f.alias or n + val = serialized.get(k, serialized.get(n)) + + if val != UNSET_SENTINEL: + if val is not None or k not in optional_fields: + m[k] = val + + return m diff --git a/src/openrouter/workspaces.py b/src/openrouter/workspaces.py index 015ceeeb..d302cb5a 100644 --- a/src/openrouter/workspaces.py +++ b/src/openrouter/workspaces.py @@ -1941,6 +1941,11 @@ def delete_budget( return unmarshal_json_response( components.DeleteWorkspaceBudgetResponse, http_res ) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + errors.BadRequestResponseErrorData, http_res + ) + raise errors.BadRequestResponseError(response_data, http_res) if utils.match_response(http_res, "401", "application/json"): response_data = unmarshal_json_response( errors.UnauthorizedResponseErrorData, http_res @@ -2074,6 +2079,287 @@ async def delete_budget_async( return unmarshal_json_response( components.DeleteWorkspaceBudgetResponse, http_res ) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + errors.BadRequestResponseErrorData, http_res + ) + raise errors.BadRequestResponseError(response_data, http_res) + if utils.match_response(http_res, "401", "application/json"): + response_data = unmarshal_json_response( + errors.UnauthorizedResponseErrorData, http_res + ) + raise errors.UnauthorizedResponseError(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, "500", "application/json"): + response_data = unmarshal_json_response( + errors.InternalServerResponseErrorData, http_res + ) + raise errors.InternalServerResponseError(response_data, http_res) + if utils.match_response(http_res, "4XX", "*"): + http_res_text = await utils.stream_to_text_async(http_res) + raise errors.OpenRouterDefaultError( + "API error occurred", http_res, http_res_text + ) + if utils.match_response(http_res, "5XX", "*"): + http_res_text = await utils.stream_to_text_async(http_res) + raise errors.OpenRouterDefaultError( + "API error occurred", http_res, http_res_text + ) + + raise errors.OpenRouterDefaultError("Unexpected response received", http_res) + + def get_budget( + self, + *, + id: str, + interval: components.WorkspaceBudgetInterval, + http_referer: Optional[str] = None, + x_open_router_title: Optional[str] = None, + x_open_router_categories: Optional[str] = None, + retries: OptionalNullable[utils.RetryConfig] = UNSET, + server_url: Optional[str] = None, + timeout_ms: Optional[int] = None, + http_headers: Optional[Mapping[str, str]] = None, + ) -> components.GetWorkspaceBudgetResponse: + r"""Get a workspace budget + + Retrieve the budget for a given interval. [Management key](/docs/guides/overview/auth/management-api-keys) required. + + :param id: The workspace ID (UUID) or slug + :param interval: Budget reset interval. Use \"lifetime\" for a one-time budget that never resets. + :param http_referer: 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. + + :param x_open_router_title: The app display name allows you to customize how your app appears in OpenRouter's dashboard. + + :param x_open_router_categories: Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings. + + :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 + :param http_headers: Additional headers to set or replace on requests. + """ + base_url = None + url_variables = None + if timeout_ms is None: + timeout_ms = self.sdk_configuration.timeout_ms + + if server_url is not None: + base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) + + request = operations.GetWorkspaceBudgetRequest( + http_referer=http_referer, + x_open_router_title=x_open_router_title, + x_open_router_categories=x_open_router_categories, + id=id, + interval=interval, + ) + + req = self._build_request( + method="GET", + path="/workspaces/{id}/budgets/{interval}", + base_url=base_url, + url_variables=url_variables, + request=request, + request_body_required=False, + request_has_path_params=True, + request_has_query_params=True, + user_agent_header="user-agent", + accept_header_value="application/json", + http_headers=http_headers, + _globals=operations.GetWorkspaceBudgetGlobals( + http_referer=self.sdk_configuration.globals.http_referer, + x_open_router_title=self.sdk_configuration.globals.x_open_router_title, + x_open_router_categories=self.sdk_configuration.globals.x_open_router_categories, + ), + security=self.sdk_configuration.security, + allow_empty_value=None, + timeout_ms=timeout_ms, + ) + + if retries == UNSET: + if self.sdk_configuration.retry_config is not UNSET: + retries = self.sdk_configuration.retry_config + else: + retries = utils.RetryConfig( + "backoff", utils.BackoffStrategy(500, 60000, 1.5, 3600000), True + ) + + retry_config = None + if isinstance(retries, utils.RetryConfig): + retry_config = (retries, ["5XX"]) + + http_res = self.do_request( + hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", + operation_id="getWorkspaceBudget", + oauth2_scopes=None, + security_source=get_security_from_env( + self.sdk_configuration.security, components.Security + ), + tags=["Workspaces"], + extensions=None, + ), + request=req, + is_error_status_code=lambda c: utils.match_status_codes(["4XX", "5XX"], c), + retry_config=retry_config, + ) + + response_data: Any = None + if utils.match_response(http_res, "200", "application/json"): + return unmarshal_json_response( + components.GetWorkspaceBudgetResponse, http_res + ) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + errors.BadRequestResponseErrorData, http_res + ) + raise errors.BadRequestResponseError(response_data, http_res) + if utils.match_response(http_res, "401", "application/json"): + response_data = unmarshal_json_response( + errors.UnauthorizedResponseErrorData, http_res + ) + raise errors.UnauthorizedResponseError(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, "500", "application/json"): + response_data = unmarshal_json_response( + errors.InternalServerResponseErrorData, http_res + ) + raise errors.InternalServerResponseError(response_data, http_res) + if utils.match_response(http_res, "4XX", "*"): + http_res_text = utils.stream_to_text(http_res) + raise errors.OpenRouterDefaultError( + "API error occurred", http_res, http_res_text + ) + if utils.match_response(http_res, "5XX", "*"): + http_res_text = utils.stream_to_text(http_res) + raise errors.OpenRouterDefaultError( + "API error occurred", http_res, http_res_text + ) + + raise errors.OpenRouterDefaultError("Unexpected response received", http_res) + + async def get_budget_async( + self, + *, + id: str, + interval: components.WorkspaceBudgetInterval, + http_referer: Optional[str] = None, + x_open_router_title: Optional[str] = None, + x_open_router_categories: Optional[str] = None, + retries: OptionalNullable[utils.RetryConfig] = UNSET, + server_url: Optional[str] = None, + timeout_ms: Optional[int] = None, + http_headers: Optional[Mapping[str, str]] = None, + ) -> components.GetWorkspaceBudgetResponse: + r"""Get a workspace budget + + Retrieve the budget for a given interval. [Management key](/docs/guides/overview/auth/management-api-keys) required. + + :param id: The workspace ID (UUID) or slug + :param interval: Budget reset interval. Use \"lifetime\" for a one-time budget that never resets. + :param http_referer: 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. + + :param x_open_router_title: The app display name allows you to customize how your app appears in OpenRouter's dashboard. + + :param x_open_router_categories: Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings. + + :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 + :param http_headers: Additional headers to set or replace on requests. + """ + base_url = None + url_variables = None + if timeout_ms is None: + timeout_ms = self.sdk_configuration.timeout_ms + + if server_url is not None: + base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) + + request = operations.GetWorkspaceBudgetRequest( + http_referer=http_referer, + x_open_router_title=x_open_router_title, + x_open_router_categories=x_open_router_categories, + id=id, + interval=interval, + ) + + req = self._build_request_async( + method="GET", + path="/workspaces/{id}/budgets/{interval}", + base_url=base_url, + url_variables=url_variables, + request=request, + request_body_required=False, + request_has_path_params=True, + request_has_query_params=True, + user_agent_header="user-agent", + accept_header_value="application/json", + http_headers=http_headers, + _globals=operations.GetWorkspaceBudgetGlobals( + http_referer=self.sdk_configuration.globals.http_referer, + x_open_router_title=self.sdk_configuration.globals.x_open_router_title, + x_open_router_categories=self.sdk_configuration.globals.x_open_router_categories, + ), + security=self.sdk_configuration.security, + allow_empty_value=None, + timeout_ms=timeout_ms, + ) + + if retries == UNSET: + if self.sdk_configuration.retry_config is not UNSET: + retries = self.sdk_configuration.retry_config + else: + retries = utils.RetryConfig( + "backoff", utils.BackoffStrategy(500, 60000, 1.5, 3600000), True + ) + + retry_config = None + if isinstance(retries, utils.RetryConfig): + retry_config = (retries, ["5XX"]) + + http_res = await self.do_request_async( + hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", + operation_id="getWorkspaceBudget", + oauth2_scopes=None, + security_source=get_security_from_env( + self.sdk_configuration.security, components.Security + ), + tags=["Workspaces"], + extensions=None, + ), + request=req, + is_error_status_code=lambda c: utils.match_status_codes(["4XX", "5XX"], c), + retry_config=retry_config, + ) + + response_data: Any = None + if utils.match_response(http_res, "200", "application/json"): + return unmarshal_json_response( + components.GetWorkspaceBudgetResponse, http_res + ) + if utils.match_response(http_res, "400", "application/json"): + response_data = unmarshal_json_response( + errors.BadRequestResponseErrorData, http_res + ) + raise errors.BadRequestResponseError(response_data, http_res) if utils.match_response(http_res, "401", "application/json"): response_data = unmarshal_json_response( errors.UnauthorizedResponseErrorData, http_res diff --git a/uv.lock b/uv.lock index 0df521a4..f06b50fa 100644 --- a/uv.lock +++ b/uv.lock @@ -213,7 +213,7 @@ wheels = [ [[package]] name = "openrouter" -version = "1.1.26" +version = "1.1.27" source = { editable = "." } dependencies = [ { name = "httpcore" },