diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock
index 5f181a91..9d72dd95 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: 3f3470ebd639b0d6b50ab320a60f53a9
+ docChecksum: 0563d6db7704a27f3b7a3beff8e602b3
docVersion: 1.0.0
speakeasyVersion: 1.787.0
generationVersion: 2.914.0
- releaseVersion: 1.2.5
- configChecksum: 7f2e7e3856c603e5ce6ad060be13db9f
+ releaseVersion: 1.2.6
+ configChecksum: 05ae5cc8c6d5b877a33c4e2e32c287e9
repoURL: https://github.com/OpenRouterTeam/python-sdk.git
installationURL: https://github.com/OpenRouterTeam/python-sdk.git
published: true
persistentEdits:
- generation_id: e6bd2316-79aa-4e76-91ac-4c6df59413d7
- pristine_commit_hash: 95795231f2423ea695b6d92c4412eadf3fcad08f
- pristine_tree_hash: 41f6f8d6a6b9875e122c91c680eb59c9c7d9495c
+ generation_id: cd46820e-de2a-481a-8817-f7dc33080f11
+ pristine_commit_hash: 5355199f997528a92ceb1f3f42c4397c90c9c430
+ pristine_tree_hash: 88a204ba1ded098bf077de095915e0893d2a3a08
features:
python:
acceptHeaders: 3.0.0
@@ -3091,8 +3091,8 @@ trackedFiles:
pristine_git_object: c9eacd7d34fe43fbad032729e0dc9d130684ed72
docs/components/internlistresponse.mdx:
id: 4c41e6189730
- last_write_checksum: sha1:b1bde1e620cf0cfc5533114aa7a6e8ca674527ba
- pristine_git_object: c3d3d07cf0e16e5475f5e61816ac383c87ec42c8
+ last_write_checksum: sha1:8253a947e183a40e10e54a21a5daecff3c1ca969
+ pristine_git_object: 75702eed180998d3c69ffb0a32932147f9946c6b
docs/components/internstatus.mdx:
id: c90242af9f30
last_write_checksum: sha1:23f8d62521ceaa0468c43d9355dba84a260058a3
@@ -7487,8 +7487,8 @@ trackedFiles:
pristine_git_object: 3a55ed59f02347866993fd5891898cec46a62c28
docs/operations/listinternsrequest.mdx:
id: e6de03b26b5e
- last_write_checksum: sha1:92926b5c50d73c315b37598d5b855a4235981196
- pristine_git_object: d1a3e4c68ed6ae8a16872fcf0226cad2130e1cb4
+ last_write_checksum: sha1:21e87a5a17a54322e2ce07eb1a334bfbc9fa3d38
+ pristine_git_object: 31c29ce6d21afd0e97d25329d704ad9e6f470f0b
docs/operations/listinternvaultsecretsglobals.mdx:
id: 83e0c9cb95c6
last_write_checksum: sha1:4def94f91a2e27836d1e4d8d313ad5bc31154d01
@@ -8047,8 +8047,8 @@ trackedFiles:
pristine_git_object: 08ef8d73c050b6baab18ef6e246a1d074179b21f
docs/sdks/byok/README.mdx:
id: 17792f3b180d
- last_write_checksum: sha1:ffe9c3546e5396fafeccd21ef2e26006c7f753ae
- pristine_git_object: 90c7b0770dbea282347030a94c2dbd14ec4eac2f
+ last_write_checksum: sha1:8e2664cb1e98c4e170fc20d364e2a3bb40715cc8
+ pristine_git_object: 4a64250d82ec39d28856b8dbcb3d3d6831ca4976
docs/sdks/chat/README.mdx:
id: 1dd859c23fe1
last_write_checksum: sha1:75cf7ecf14bdaae4b3e2c767dc3d2c9d9e41d31c
@@ -8099,8 +8099,8 @@ trackedFiles:
pristine_git_object: 08c687694efbecf50406ae7929029d39fb121295
docs/sdks/interns/README.mdx:
id: 2f8a053ffe78
- last_write_checksum: sha1:cd08ad1f1a3c790b2cc2cbdc51ba6ba7d7e80000
- pristine_git_object: b4aaf9cfe9f4859b9c6b41d5bd6133846bc07092
+ last_write_checksum: sha1:a1a2bf31ac879e14767dddc88fa87e98046ef925
+ pristine_git_object: 8fc5e6b9bb5d4626033ffd3f745f9fe49bd106fd
docs/sdks/models/README.mdx:
id: 58f1ca464e0b
last_write_checksum: sha1:093dd30ebdd18b9763a6956915e0dcae4ae7d5e5
@@ -8163,8 +8163,8 @@ trackedFiles:
pristine_git_object: 3e38f1a929f7d6b1d6de74604aa87e3d8f010544
pyproject.toml:
id: 5d07e7d72637
- last_write_checksum: sha1:140a643bff5a9bd5da8b434162f752c62ef2d8ea
- pristine_git_object: 18fe26f0d58a56819595fa9e6296bf8440564cdd
+ last_write_checksum: sha1:7d46ef8090d156637d78acb4572fce19c2dfca3a
+ pristine_git_object: 3a5ee39e26552427fbfee31d044fa1a2403e9bb9
scripts/prepare_readme.py:
id: e0c5957a6035
last_write_checksum: sha1:77f44b60b98bc126557ec27391f91dfba764bb54
@@ -8191,8 +8191,8 @@ trackedFiles:
pristine_git_object: 86713cfea633e09d33b3d4e65281071fe20e6137
src/openrouter/_version.py:
id: d8d15ad6c586
- last_write_checksum: sha1:b82f3c4515d029546aa3cc8bc92de92ca3cd588c
- pristine_git_object: 7a2e6e0536d24d9405a9e06f3db0db5cb492ae15
+ last_write_checksum: sha1:3ab3cae82bacc5b29e795e4ae0476e3a305fa10f
+ pristine_git_object: 5c8bfcc8c2dba49f06b2d7e2c5cb57787224c2f1
src/openrouter/alpha.py:
id: 306c4d93308d
last_write_checksum: sha1:0c25a52ed5fb688ec1e923e4e82bcfc9cae49465
@@ -8223,8 +8223,8 @@ trackedFiles:
pristine_git_object: 412aed86e32b1fd166d27e06e562463fa2b04395
src/openrouter/byok.py:
id: bec352462ae1
- last_write_checksum: sha1:0dd1c12b4b192531a3d5926e2793d1ac421afa17
- pristine_git_object: 32d921e7d8d46ec11417a8e243185cd0f37633ca
+ last_write_checksum: sha1:ddb52d17b77021f5d53ab22fb9ffef447a61682e
+ pristine_git_object: 22834caf78784ff99d3be6cd4fe3f4eea01ac859
src/openrouter/chat.py:
id: 723fdce15c1d
last_write_checksum: sha1:1a4e5375fb95884be6db0f508e1c2c9cda27b20e
@@ -9611,8 +9611,8 @@ trackedFiles:
pristine_git_object: 589fcd031d428922ff76b506ea068fc746425a1c
src/openrouter/components/internlistresponse.py:
id: 1d6ce743dbed
- last_write_checksum: sha1:51cf92ca51b0d90a127bf9fd8a150b4063a4ad70
- pristine_git_object: 941c3861bb2d78e8b696b1d7d3632e9baf96c343
+ last_write_checksum: sha1:ffb97c9bdd1ccca6cfe9951cd0ae0297e4525765
+ pristine_git_object: 2afe11472e1f3861b2b9725ddafd036b961d3088
src/openrouter/components/itemreferenceitem.py:
id: d3c42b5f11fb
last_write_checksum: sha1:25fd74f1c34307a97931e1d2c138a1db347218ad
@@ -11135,8 +11135,8 @@ trackedFiles:
pristine_git_object: 50643a126668498dd668c7cceb9f78c03d413d32
src/openrouter/interns.py:
id: d18df05c5c6d
- last_write_checksum: sha1:cf5c9ca74c5f31607eeb508bcb97078e8f0038be
- pristine_git_object: 5272d44fdabfa2c5ab926de6c533875ff0571926
+ last_write_checksum: sha1:cad4e1386e159c796d926eeacc0f658208e9c102
+ pristine_git_object: 705236ee7435e3cd591571b81cf5f67ed9cbebd7
src/openrouter/models/__init__.py:
id: ed73b93abb3f
last_write_checksum: sha1:932a790ae66ccd7d7022b39c659bcf72a664ebea
@@ -11499,8 +11499,8 @@ trackedFiles:
pristine_git_object: 01655ae02036acf433ec5f54fd1d9323a55f0684
src/openrouter/operations/listinterns.py:
id: 89bc4fa38c9f
- last_write_checksum: sha1:4cafb99a7020b6199c7f57c36f111508ab18da49
- pristine_git_object: 003e212711b2436ee4af5efe3905932ea1e59371
+ last_write_checksum: sha1:a73fccd1268f4586f5adc3477ed21011a914eb9a
+ pristine_git_object: f782b7b4230850b68af902f813083140ab28fb82
src/openrouter/operations/listinternvaultsecrets.py:
id: d9f9db46871d
last_write_checksum: sha1:31bd0f67cb4e7dffe16c4a4af5d27a08920d355c
@@ -12717,6 +12717,8 @@ examples:
application/json: {"error": {"code": 404, "message": "Resource not found"}}
"500":
application/json: {"error": {"code": 500, "message": "Internal Server Error"}}
+ "403":
+ application/json: {"error": {"code": 403, "message": "Only management keys can perform this operation"}}
getAppRankings:
speakeasy-default-get-app-rankings:
parameters:
@@ -14953,4 +14955,4 @@ examples:
"502":
application/json: {"error": {"code": 409, "message": "That question is no longer waiting for an answer."}}
examplesVersion: 1.0.2
-releaseNotes: "## Python SDK Changes:\n* `open_router.interns.delete_intern()`: \n * `request.acknowledge_workspace_loss` **Added**\n * `error` **Changed**\n"
+releaseNotes: "## Python SDK Changes:\n* `open_router.byok.update()`: `error.status[403]` **Added**\n* `open_router.interns.list_interns()`: \n * `request.starting_after` **Added**\n * `response.next_cursor` **Added**\n"
diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml
index 6fa73af5..edbd8d3f 100644
--- a/.speakeasy/gen.yaml
+++ b/.speakeasy/gen.yaml
@@ -36,7 +36,7 @@ generation:
documentation: mintlify
preApplyUnionDiscriminators: true
python:
- version: 1.2.5
+ version: 1.2.6
additionalDependencies:
dev: {}
main: {}
diff --git a/.speakeasy/out.openapi.yaml b/.speakeasy/out.openapi.yaml
index 094b1848..0e9b8157 100644
--- a/.speakeasy/out.openapi.yaml
+++ b/.speakeasy/out.openapi.yaml
@@ -13088,6 +13088,10 @@ components:
has_more:
description: 'True when more interns match the current filters.'
type: 'boolean'
+ next_cursor:
+ description: 'Opaque cursor, present when `has_more` is true. Pass it as `starting_after` to fetch the next page.'
+ example: 'MjAyNi0wOS0xNlQwODozMDowMC4wMDAwMDBafDdjOWU2Njc5LTc0MjUtNDBkZS05NDRiLWUwN2ZjMWY5MGFlNw'
+ type: 'string'
required:
- 'data'
- 'has_more'
@@ -31803,6 +31807,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:
@@ -36365,6 +36379,14 @@ paths:
x-speakeasy-unknown-values: allow
type: 'array'
style: 'form'
+ - description: 'The opaque `next_cursor` of the previous page. Returns the interns that come after it in the newest-first order. A malformed cursor is a 400.'
+ in: 'query'
+ name: 'starting_after'
+ required: false
+ schema:
+ description: 'The opaque `next_cursor` of the previous page. Returns the interns that come after it in the newest-first order. A malformed cursor is a 400.'
+ example: 'MjAyNi0wOS0xNlQwODozMDowMC4wMDAwMDBafDdjOWU2Njc5LTc0MjUtNDBkZS05NDRiLWUwN2ZjMWY5MGFlNw'
+ type: 'string'
- description: 'Only return interns in this workspace. It must match the API key workspace.'
in: 'query'
name: 'workspace_id'
@@ -40584,9 +40606,13 @@ paths:
'403':
content:
application/json:
+ example:
+ error:
+ code: 403
+ message: 'Only management keys can perform this operation'
schema:
$ref: '#/components/schemas/ForbiddenResponse'
- description: 'Privacy settings are locked'
+ description: 'Forbidden - Authentication successful but insufficient permissions'
'404':
content:
application/json:
diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock
index 31db30b7..30639281 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:6c09ee03206f9286c389f9cf9296b4e34c381c3b383ae873253e4f38cb64f11d
- sourceBlobDigest: sha256:05e64270223712bbf5b880b35cee94962efcc130ff9773f4332e5fc94f4512a0
+ sourceRevisionDigest: sha256:c66839243c891c6f582939dd68bc390fd56629095966346707bd300524c73e39
+ sourceBlobDigest: sha256:0b66f3175e7b0f14ae3b22216c39295715cfd827ce73f569c2d4b012c4b91418
tags:
- latest
- 1.0.0
@@ -11,10 +11,10 @@ targets:
open-router:
source: OpenRouter API
sourceNamespace: open-router-chat-completions-api
- sourceRevisionDigest: sha256:6c09ee03206f9286c389f9cf9296b4e34c381c3b383ae873253e4f38cb64f11d
- sourceBlobDigest: sha256:05e64270223712bbf5b880b35cee94962efcc130ff9773f4332e5fc94f4512a0
+ sourceRevisionDigest: sha256:c66839243c891c6f582939dd68bc390fd56629095966346707bd300524c73e39
+ sourceBlobDigest: sha256:0b66f3175e7b0f14ae3b22216c39295715cfd827ce73f569c2d4b012c4b91418
codeSamplesNamespace: open-router-python-code-samples
- codeSamplesRevisionDigest: sha256:5f47abce5f532756d300ba4aa6fb317d628f6f66011cd233e89a9a24c6b4be2a
+ codeSamplesRevisionDigest: sha256:aa75ffe5aa1ebe652c8f1cf14a4813b6794989325e6798be7517cfcbdb81693f
workflow:
workflowVersion: 1.0.0
speakeasyVersion: 1.787.0
diff --git a/RELEASES.md b/RELEASES.md
index b96dbf08..d8da5301 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -2459,4 +2459,14 @@ Based on:
### Generated
- [python v1.2.5] .
### Releases
-- [PyPI v1.2.5] https://pypi.org/project/openrouter/1.2.5 - .
\ No newline at end of file
+- [PyPI v1.2.5] https://pypi.org/project/openrouter/1.2.5 - .
+
+## 2026-09-19 21:24:33
+### Changes
+Based on:
+- OpenAPI Doc
+- Speakeasy CLI 1.787.0 (2.914.0) https://github.com/speakeasy-api/speakeasy
+### Generated
+- [python v1.2.6] .
+### Releases
+- [PyPI v1.2.6] https://pypi.org/project/openrouter/1.2.6 - .
\ No newline at end of file
diff --git a/docs/components/internlistresponse.mdx b/docs/components/internlistresponse.mdx
index c3d3d07c..75702eed 100644
--- a/docs/components/internlistresponse.mdx
+++ b/docs/components/internlistresponse.mdx
@@ -7,7 +7,8 @@ Interns visible to the authenticated API key.
## Fields
-| Field | Type | Required | Description |
-| -------------------------------------------------- | -------------------------------------------------- | -------------------------------------------------- | -------------------------------------------------- |
-| `data` | List[[components.Intern](../components/intern.mdx)] | :heavy_check_mark: | N/A |
-| `has_more` | *bool* | :heavy_check_mark: | True when more interns match the current filters. |
\ No newline at end of file
+| Field | Type | Required | Description | Example |
+| --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
+| `data` | List[[components.Intern](../components/intern.mdx)] | :heavy_check_mark: | N/A | |
+| `has_more` | *bool* | :heavy_check_mark: | True when more interns match the current filters. | |
+| `next_cursor` | *Optional[str]* | :heavy_minus_sign: | Opaque cursor, present when `has_more` is true. Pass it as `starting_after` to fetch the next page. | MjAyNi0wOS0xNlQwODozMDowMC4wMDAwMDBafDdjOWU2Njc5LTc0MjUtNDBkZS05NDRiLWUwN2ZjMWY5MGFlNw |
\ No newline at end of file
diff --git a/docs/operations/listinternsrequest.mdx b/docs/operations/listinternsrequest.mdx
index d1a3e4c6..31c29ce6 100644
--- a/docs/operations/listinternsrequest.mdx
+++ b/docs/operations/listinternsrequest.mdx
@@ -11,4 +11,5 @@ title: "ListInternsRequest"
| `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.
| |
| `limit` | *Optional[int]* | :heavy_minus_sign: | Maximum number of interns to return, from 1 through 500. | 50 |
| `status` | List[[operations.Status](../operations/status.mdx)] | :heavy_minus_sign: | Comma-separated lifecycle statuses to include. | [
"queued",
"running"
] |
+| `starting_after` | *Optional[str]* | :heavy_minus_sign: | The opaque `next_cursor` of the previous page. Returns the interns that come after it in the newest-first order. A malformed cursor is a 400. | MjAyNi0wOS0xNlQwODozMDowMC4wMDAwMDBafDdjOWU2Njc5LTc0MjUtNDBkZS05NDRiLWUwN2ZjMWY5MGFlNw |
| `workspace_id` | *Optional[str]* | :heavy_minus_sign: | Only return interns in this workspace. It must match the API key workspace. | 89f9f5b2-3f89-4eaf-83ca-5ceae149e8bb |
\ No newline at end of file
diff --git a/docs/sdks/byok/README.mdx b/docs/sdks/byok/README.mdx
index 90c7b077..4a64250d 100644
--- a/docs/sdks/byok/README.mdx
+++ b/docs/sdks/byok/README.mdx
@@ -277,6 +277,7 @@ with OpenRouter(
| ---------------------------------- | ---------------------------------- | ---------------------------------- |
| errors.BadRequestResponseError | 400 | application/json |
| errors.UnauthorizedResponseError | 401 | application/json |
+| errors.ForbiddenResponseError | 403 | application/json |
| errors.NotFoundResponseError | 404 | application/json |
| errors.InternalServerResponseError | 500 | application/json |
| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* |
\ No newline at end of file
diff --git a/docs/sdks/interns/README.mdx b/docs/sdks/interns/README.mdx
index b4aaf9cf..8fc5e6b9 100644
--- a/docs/sdks/interns/README.mdx
+++ b/docs/sdks/interns/README.mdx
@@ -52,6 +52,7 @@ with OpenRouter(
| `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.
| |
| `limit` | *Optional[int]* | :heavy_minus_sign: | Maximum number of interns to return, from 1 through 500. | 50 |
| `status` | List[[operations.Status](../../operations/status.mdx)] | :heavy_minus_sign: | Comma-separated lifecycle statuses to include. | [
"queued",
"running"
] |
+| `starting_after` | *Optional[str]* | :heavy_minus_sign: | The opaque `next_cursor` of the previous page. Returns the interns that come after it in the newest-first order. A malformed cursor is a 400. | MjAyNi0wOS0xNlQwODozMDowMC4wMDAwMDBafDdjOWU2Njc5LTc0MjUtNDBkZS05NDRiLWUwN2ZjMWY5MGFlNw |
| `workspace_id` | *Optional[str]* | :heavy_minus_sign: | Only return interns in this workspace. It must match the API key workspace. | 89f9f5b2-3f89-4eaf-83ca-5ceae149e8bb |
| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.mdx) | :heavy_minus_sign: | Configuration to override the default retry behavior of the client. | |
diff --git a/pyproject.toml b/pyproject.toml
index 18fe26f0..3a5ee39e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "openrouter"
-version = "1.2.5"
+version = "1.2.6"
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 7a2e6e05..5c8bfcc8 100644
--- a/src/openrouter/_version.py
+++ b/src/openrouter/_version.py
@@ -3,10 +3,10 @@
import importlib.metadata
__title__: str = "openrouter"
-__version__: str = "1.2.5"
+__version__: str = "1.2.6"
__openapi_doc_version__: str = "1.0.0"
__gen_version__: str = "2.914.0"
-__user_agent__: str = "speakeasy-sdk/python 1.2.5 2.914.0 1.0.0 openrouter"
+__user_agent__: str = "speakeasy-sdk/python 1.2.6 2.914.0 1.0.0 openrouter"
try:
if __package__ is not None:
diff --git a/src/openrouter/byok.py b/src/openrouter/byok.py
index 32d921e7..22834caf 100644
--- a/src/openrouter/byok.py
+++ b/src/openrouter/byok.py
@@ -1378,6 +1378,11 @@ 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
@@ -1553,6 +1558,11 @@ 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
diff --git a/src/openrouter/components/internlistresponse.py b/src/openrouter/components/internlistresponse.py
index 941c3861..2afe1147 100644
--- a/src/openrouter/components/internlistresponse.py
+++ b/src/openrouter/components/internlistresponse.py
@@ -2,9 +2,10 @@
from __future__ import annotations
from .intern import Intern, InternTypedDict
-from openrouter.types import BaseModel
-from typing import List
-from typing_extensions import TypedDict
+from openrouter.types import BaseModel, UNSET_SENTINEL
+from pydantic import model_serializer
+from typing import List, Optional
+from typing_extensions import NotRequired, TypedDict
class InternListResponseTypedDict(TypedDict):
@@ -13,6 +14,8 @@ class InternListResponseTypedDict(TypedDict):
data: List[InternTypedDict]
has_more: bool
r"""True when more interns match the current filters."""
+ next_cursor: NotRequired[str]
+ r"""Opaque cursor, present when `has_more` is true. Pass it as `starting_after` to fetch the next page."""
class InternListResponse(BaseModel):
@@ -22,3 +25,22 @@ class InternListResponse(BaseModel):
has_more: bool
r"""True when more interns match the current filters."""
+
+ next_cursor: Optional[str] = None
+ r"""Opaque cursor, present when `has_more` is true. Pass it as `starting_after` to fetch the next page."""
+
+ @model_serializer(mode="wrap")
+ def serialize_model(self, handler):
+ optional_fields = set(["next_cursor"])
+ 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/interns.py b/src/openrouter/interns.py
index 5272d44f..705236ee 100644
--- a/src/openrouter/interns.py
+++ b/src/openrouter/interns.py
@@ -20,6 +20,7 @@ def list_interns(
x_open_router_categories: Optional[str] = None,
limit: Optional[int] = None,
status: Optional[Iterable[operations.Status]] = None,
+ starting_after: Optional[str] = None,
workspace_id: Optional[str] = None,
retries: OptionalNullable[utils.RetryConfig] = UNSET,
server_url: Optional[str] = None,
@@ -41,6 +42,7 @@ def list_interns(
:param limit: Maximum number of interns to return, from 1 through 500.
:param status: Comma-separated lifecycle statuses to include.
+ :param starting_after: The opaque `next_cursor` of the previous page. Returns the interns that come after it in the newest-first order. A malformed cursor is a 400.
:param workspace_id: Only return interns in this workspace. It must match the API key workspace.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
@@ -63,6 +65,7 @@ def list_interns(
x_open_router_categories=x_open_router_categories,
limit=limit,
status=utils.unmarshal(status, Optional[List[operations.Status]]),
+ starting_after=starting_after,
workspace_id=workspace_id,
)
@@ -154,6 +157,7 @@ async def list_interns_async(
x_open_router_categories: Optional[str] = None,
limit: Optional[int] = None,
status: Optional[Iterable[operations.Status]] = None,
+ starting_after: Optional[str] = None,
workspace_id: Optional[str] = None,
retries: OptionalNullable[utils.RetryConfig] = UNSET,
server_url: Optional[str] = None,
@@ -175,6 +179,7 @@ async def list_interns_async(
:param limit: Maximum number of interns to return, from 1 through 500.
:param status: Comma-separated lifecycle statuses to include.
+ :param starting_after: The opaque `next_cursor` of the previous page. Returns the interns that come after it in the newest-first order. A malformed cursor is a 400.
:param workspace_id: Only return interns in this workspace. It must match the API key workspace.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
@@ -197,6 +202,7 @@ async def list_interns_async(
x_open_router_categories=x_open_router_categories,
limit=limit,
status=utils.unmarshal(status, Optional[List[operations.Status]]),
+ starting_after=starting_after,
workspace_id=workspace_id,
)
diff --git a/src/openrouter/operations/listinterns.py b/src/openrouter/operations/listinterns.py
index 003e2127..f782b7b4 100644
--- a/src/openrouter/operations/listinterns.py
+++ b/src/openrouter/operations/listinterns.py
@@ -106,6 +106,8 @@ class ListInternsRequestTypedDict(TypedDict):
r"""Maximum number of interns to return, from 1 through 500."""
status: NotRequired[List[Status]]
r"""Comma-separated lifecycle statuses to include."""
+ starting_after: NotRequired[str]
+ r"""The opaque `next_cursor` of the previous page. Returns the interns that come after it in the newest-first order. A malformed cursor is a 400."""
workspace_id: NotRequired[str]
r"""Only return interns in this workspace. It must match the API key workspace."""
@@ -151,6 +153,12 @@ class ListInternsRequest(BaseModel):
] = None
r"""Comma-separated lifecycle statuses to include."""
+ starting_after: Annotated[
+ Optional[str],
+ FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
+ ] = None
+ r"""The opaque `next_cursor` of the previous page. Returns the interns that come after it in the newest-first order. A malformed cursor is a 400."""
+
workspace_id: Annotated[
Optional[str],
FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
@@ -166,6 +174,7 @@ def serialize_model(self, handler):
"X-OpenRouter-Categories",
"limit",
"status",
+ "starting_after",
"workspace_id",
]
)
diff --git a/uv.lock b/uv.lock
index 7fbdaf8c..83bda36c 100644
--- a/uv.lock
+++ b/uv.lock
@@ -213,7 +213,7 @@ wheels = [
[[package]]
name = "openrouter"
-version = "1.2.5"
+version = "1.2.6"
source = { editable = "." }
dependencies = [
{ name = "httpcore" },