From df34f7a79889c32d824a894227b652f9217cb2a0 Mon Sep 17 00:00:00 2001 From: speakeasybot Date: Thu, 3 Sep 2026 00:28:09 +0000 Subject: [PATCH 1/2] ## Python SDK Changes: * `open_router.o_auth.list_oauth_jwks()`: **Added** * `open_router.o_auth.create_oauth_token()`: **Added** --- .speakeasy/gen.lock | 171 +++++- .speakeasy/gen.yaml | 2 +- .speakeasy/out.openapi.yaml | 235 ++++++++ .speakeasy/workflow.lock | 10 +- RELEASES.md | 12 +- docs/components/alg.mdx | 15 + docs/components/crv.mdx | 15 + docs/components/errorenum.mdx | 24 + docs/components/granttype.mdx | 17 + docs/components/issuedtokentype.mdx | 15 + docs/components/key.mdx | 15 + docs/components/kty.mdx | 15 + docs/components/oauthjwks.mdx | 12 + docs/components/requestedtokentype.mdx | 17 + docs/components/scope.mdx | 17 + docs/components/subjecttokentype.mdx | 17 + docs/components/tokenexchangerequest.mdx | 17 + docs/components/tokenexchangeresponse.mdx | 16 + docs/components/tokentype.mdx | 15 + docs/components/use.mdx | 15 + docs/errors/oautherrorresponse.mdx | 13 + docs/operations/createoauthtokenglobals.mdx | 11 + docs/operations/createoauthtokenrequest.mdx | 12 + docs/operations/listoauthjwksglobals.mdx | 11 + docs/operations/listoauthjwksrequest.mdx | 11 + docs/sdks/oauth/README.mdx | 101 +++- pyproject.toml | 2 +- src/openrouter/_version.py | 4 +- src/openrouter/components/__init__.py | 63 +++ .../components/oautherrorresponse.py | 18 + src/openrouter/components/oauthjwks.py | 56 ++ .../components/tokenexchangerequest.py | 81 +++ .../components/tokenexchangeresponse.py | 40 ++ src/openrouter/errors/__init__.py | 5 + src/openrouter/errors/oautherrorresponse.py | 31 ++ src/openrouter/oauth.py | 524 ++++++++++++++++++ src/openrouter/operations/__init__.py | 28 + src/openrouter/operations/createoauthtoken.py | 150 +++++ src/openrouter/operations/listoauthjwks.py | 137 +++++ uv.lock | 2 +- 40 files changed, 1939 insertions(+), 33 deletions(-) create mode 100644 docs/components/alg.mdx create mode 100644 docs/components/crv.mdx create mode 100644 docs/components/errorenum.mdx create mode 100644 docs/components/granttype.mdx create mode 100644 docs/components/issuedtokentype.mdx create mode 100644 docs/components/key.mdx create mode 100644 docs/components/kty.mdx create mode 100644 docs/components/oauthjwks.mdx create mode 100644 docs/components/requestedtokentype.mdx create mode 100644 docs/components/scope.mdx create mode 100644 docs/components/subjecttokentype.mdx create mode 100644 docs/components/tokenexchangerequest.mdx create mode 100644 docs/components/tokenexchangeresponse.mdx create mode 100644 docs/components/tokentype.mdx create mode 100644 docs/components/use.mdx create mode 100644 docs/errors/oautherrorresponse.mdx create mode 100644 docs/operations/createoauthtokenglobals.mdx create mode 100644 docs/operations/createoauthtokenrequest.mdx create mode 100644 docs/operations/listoauthjwksglobals.mdx create mode 100644 docs/operations/listoauthjwksrequest.mdx create mode 100644 src/openrouter/components/oautherrorresponse.py create mode 100644 src/openrouter/components/oauthjwks.py create mode 100644 src/openrouter/components/tokenexchangerequest.py create mode 100644 src/openrouter/components/tokenexchangeresponse.py create mode 100644 src/openrouter/errors/oautherrorresponse.py create mode 100644 src/openrouter/operations/createoauthtoken.py create mode 100644 src/openrouter/operations/listoauthjwks.py diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock index c07f6bc8..81219d48 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: 8d1ddcb1ec40d884db93bc0db665e440 + docChecksum: 8d66cbc3cfd2e7025585831c83519a81 docVersion: 1.0.0 speakeasyVersion: 1.787.0 generationVersion: 2.914.0 - releaseVersion: 1.1.118 - configChecksum: c034902d1804d4170bfff0b2e1c583c4 + releaseVersion: 1.1.119 + configChecksum: 40337010eb197dfba7772005df02c9d3 repoURL: https://github.com/OpenRouterTeam/python-sdk.git installationURL: https://github.com/OpenRouterTeam/python-sdk.git published: true persistentEdits: - generation_id: 7739462e-9ce4-4dfa-b3ff-ccc39ba1b359 - pristine_commit_hash: 87f34637ee9a2df6045dcfaa21af3a6d5c3ce128 - pristine_tree_hash: c28da05c4b6f752b736de8664bd83fe1327d1ac6 + generation_id: d3759cae-8d5c-4171-a425-8c2a349d4e4a + pristine_commit_hash: bd2f9eb6bd8e1c4f8e629fbdb730f131bcc7aa36 + pristine_tree_hash: 26f19ced7941d9fff89a5d2453ac7c57d596fb3e features: python: acceptHeaders: 3.0.0 @@ -176,6 +176,10 @@ trackedFiles: id: d16eed88b27f last_write_checksum: sha1:f1b71145d88842c0b61651b24f1b7245ece6620d pristine_git_object: 4acb9c2305ede0ba0e6596e3c2b8d261ff24e12d + docs/components/alg.mdx: + id: 1d2a2f0cf3ba + last_write_checksum: sha1:db396bc8d5e654b34b7c50709a978a0c0da3cfbd + pristine_git_object: 40fd32366dbcdd3fd91aa4bb2687208c05c12691 docs/components/allowedcaller.mdx: id: ad714fd6c0df last_write_checksum: sha1:b0834e5088da9d409d72ac7e4184f067e4dbee62 @@ -1656,6 +1660,10 @@ trackedFiles: id: ee0c0ca3257e last_write_checksum: sha1:f6de7351ddd4d0bb8990ef8e40d8cdfb24fe6c53 pristine_git_object: aee384f40812ab73fa2a94ee1ee24decaee754f3 + docs/components/crv.mdx: + id: bd891a5d3518 + last_write_checksum: sha1:d95f00e04283964e9fd32dfe2d4f1825d07f810c + pristine_git_object: 5164338698e2194e88ddf0b9b4c4755733adf620 docs/components/customtool.mdx: id: e8963a9be6e2 last_write_checksum: sha1:9321bedb7d51af8f98dfe098989747d92a3f8db8 @@ -1900,6 +1908,10 @@ trackedFiles: id: 0d3bc0f8a92d last_write_checksum: sha1:ad3ff0627e50e0b51140afaf8fa9b08531f5e9c4 pristine_git_object: c177e3075bf9bf8b124fc5bb0c54eff0a2a75ae6 + docs/components/errorenum.mdx: + id: 722594694be3 + last_write_checksum: sha1:2049d2c991cd1fc6b678b44cba040d382eb3b133 + pristine_git_object: 95a2d3dcd8e7a45e6c31fcaa912c5df0f2038eba docs/components/errorevent.mdx: id: b8087272db82 last_write_checksum: sha1:af1ab64010fd36ba6711e26788244afcbf35d9c9 @@ -2304,6 +2316,10 @@ trackedFiles: id: c8d0c4683019 last_write_checksum: sha1:5d10c3c4510cdc869a740deee62c31e9d2b02cc9 pristine_git_object: 42ef3f3487d6e55ad13f7ae93edd146fd46332bf + docs/components/granttype.mdx: + id: f8403fbcc98a + last_write_checksum: sha1:4dbfadaf6168b7b65f581a15d54b0b42e6f674ea + pristine_git_object: 6e17644dffb3aef799758f46d5ac781114b58c1f docs/components/guardrail.mdx: id: 91791d4c83b6 last_write_checksum: sha1:6f8af0e14ef12e99132304a903cc2e68adff68a0 @@ -2764,6 +2780,10 @@ trackedFiles: id: 9a443dea63c5 last_write_checksum: sha1:39c41704820f6cde2d67ec3b9f1bcac7bc1a81d0 pristine_git_object: 8ddf14e86902b5d1b69fd15b7098e489c741b993 + docs/components/issuedtokentype.mdx: + id: b5c747e2aaf8 + last_write_checksum: sha1:33d9e8b021a11c7168f66a288dd5d7ed3aa0a78e + pristine_git_object: cca4300fb4e717e034d840a18ae47bdd8a2e65b6 docs/components/itemreferenceitem.mdx: id: e6a76e3841f0 last_write_checksum: sha1:715bc829e2cc02c156eb742a88145113fbd7449c @@ -2788,10 +2808,18 @@ trackedFiles: id: 381355e7a9b0 last_write_checksum: sha1:757294dcf376127b5cb8ef8224b848695c9b2c7f pristine_git_object: 99cde727d78d8a158b1d809de1841e083507f13a + docs/components/key.mdx: + id: d16f98f55d22 + last_write_checksum: sha1:7b1cb03f0c923bea067e417499df57e1c9eae863 + pristine_git_object: 48c2e08317be0d77a3ce91d4afc36678995c5fff docs/components/keyassignment.mdx: id: 6ebc78938625 last_write_checksum: sha1:cc00184ca2e96cb429788698d7be2111a2ea5fad pristine_git_object: 3c18ed0fb80fbc8cfd45667af06cdecde6a907d5 + docs/components/kty.mdx: + id: e031cc3f462c + last_write_checksum: sha1:2506bc8b4e80b7b71b9f59a8d84a0367cfd3a119 + pristine_git_object: bfef4620305e6517f0de3179cc1b9359ca3e43d2 docs/components/legacychatcontentvideo.mdx: id: fd222b8b9445 last_write_checksum: sha1:d6819bc122734d7dbe9abf060ae31bac61361633 @@ -3264,6 +3292,10 @@ trackedFiles: id: 7c59a9c21347 last_write_checksum: sha1:2070aa94c1db3bbfe3cfb242c63514ad15f3b4d4 pristine_git_object: e0bc365ca79475fa53de95da69e7c42e8a26a391 + docs/components/oauthjwks.mdx: + id: 95e16bc8c6fb + last_write_checksum: sha1:81307bc7bf42460514498c8dd4f1aee87886cda7 + pristine_git_object: 463ee9cd6a8eb9089700e17d1e6166d5bfb2078d docs/components/observabilityarizedestination.mdx: id: 8ab5c92ec9b5 last_write_checksum: sha1:95a8e27c3dec38da7c3cefb0a9b5d81ae7a17c49 @@ -4696,6 +4728,10 @@ trackedFiles: id: f2abab6453b6 last_write_checksum: sha1:9db11174ef8a40a144f94ec1d18cb4500fc66871 pristine_git_object: 51b26cc819421478797a67e192f2c8952cab45a4 + docs/components/requestedtokentype.mdx: + id: b9ec16a07b4f + last_write_checksum: sha1:4dc1c7aaac97bca551c291d8e8ff8444de911f5d + pristine_git_object: 1994454b346f76bdea0b1c98bfba57eda2469171 docs/components/requesttimeoutresponseerrordata.mdx: id: 6f984fda78d6 last_write_checksum: sha1:bc2a0f98b623f4382ee1872cf8088477d81dd7c4 @@ -4820,6 +4856,10 @@ trackedFiles: id: 0306b7b3cf78 last_write_checksum: sha1:93f2d7d1dc60a2b1635202d83ae9f00cc314e2e6 pristine_git_object: 94331ee57f8ebf2b21903d5ebda22e0faf23044a + docs/components/scope.mdx: + id: 25b03f56752e + last_write_checksum: sha1:604855944477d8965aa373bbba3c15fa77a8b70d + pristine_git_object: ca4b238ce6dbfdbdfc9c93c11d9232c83ca14018 docs/components/searchcontextsizeenum.mdx: id: b6b9a99acb5f last_write_checksum: sha1:177016c42a56a7a8dcd40caa7e9105ca7a6ea1cc @@ -5160,6 +5200,10 @@ trackedFiles: id: 36a519fbf209 last_write_checksum: sha1:14f4bf5f550f0dfddb8bd950e000ed431a5470e9 pristine_git_object: a93cd73684c2a51b27f8a1e13a09f980a676567e + docs/components/subjecttokentype.mdx: + id: 0573e325c2b6 + last_write_checksum: sha1:8b6379150e9ed64054379336bf1d32ac868e09be + pristine_git_object: 3e6f988ecc0a7b7857963ebec2be310ab7d6a8d2 docs/components/submitgenerationfeedbackrequest.mdx: id: fba2401919b4 last_write_checksum: sha1:0c574d3011a3b5c9183697be0484a019188b5ec0 @@ -5268,6 +5312,18 @@ trackedFiles: id: f8f7eb6e6313 last_write_checksum: sha1:4061554783746bdb572dc5eb4ae678a677fc6c5e pristine_git_object: 8d52bfaecf3fa301b6e9466ed356adb0b9202085 + docs/components/tokenexchangerequest.mdx: + id: c1564eb38361 + last_write_checksum: sha1:e91d2e5d15beff1038a83015adf13f3feb075819 + pristine_git_object: 84a147af188137886dab4d40ff7c64cd1cec822f + docs/components/tokenexchangeresponse.mdx: + id: 5b7eb37933eb + last_write_checksum: sha1:a0fb15d00227686dfe83a567178d71d3a7c7c710 + pristine_git_object: c3a8de52d28aeafb3daf7e9f12b19782b3aa582e + docs/components/tokentype.mdx: + id: 0c9b63e6ad84 + last_write_checksum: sha1:015804b1c1b1e656b35d22e1a348649dd5d11cda + pristine_git_object: 31766573c9bca4b802b8e9a386595febebfe8a08 docs/components/tooladvisor20260301.mdx: id: df2858dddd07 last_write_checksum: sha1:368a170e20857d634bf0295c49689d800c3d08ee @@ -5704,6 +5760,10 @@ trackedFiles: id: 95d8a52fead9 last_write_checksum: sha1:a219616ceea34ec8687c7fda95c9214404978d19 pristine_git_object: f7efeafacd0f11565d6bcf8e44011cc64a6a7cdb + docs/components/use.mdx: + id: 8549fc023932 + last_write_checksum: sha1:48e2dacda7b19f4c4439f7754c8de8dd5147878e + pristine_git_object: 4590a4bc9870cd9abfa5b865bcc16a151f876dfd docs/components/userlocation.mdx: id: d197ccf2b36c last_write_checksum: sha1:c7078ea2cd00c001dcef6ce68c790b9d3d718e2b @@ -5944,6 +6004,10 @@ trackedFiles: id: a387a1eb646c last_write_checksum: sha1:c31fd704f361e6d1d568d734c469fa9c37095f9f pristine_git_object: 5ba79a1971d60ca1b9206e13512beef48e6b1c47 + docs/errors/oautherrorresponse.mdx: + id: 67679ef5658c + last_write_checksum: sha1:df1d77636f204cd0911be0f8e1cc9006830dec78 + pristine_git_object: 9d1631687b3924fb6c3b3c0c03cc2af41ee745d0 docs/errors/payloadtoolargeresponseerror.mdx: id: a2428bf1899b last_write_checksum: sha1:79e6cd4573d4513e697f28905946946a114c6812 @@ -6208,6 +6272,14 @@ trackedFiles: id: 08e825fab080 last_write_checksum: sha1:268c49a74956884d1e3b3495fdf6ee6c7383e323 pristine_git_object: 83f6a2a6ba3926b76f509b84b7a41bc0e10e6d58 + docs/operations/createoauthtokenglobals.mdx: + id: 253b06bd452b + last_write_checksum: sha1:9f7cedf50a8fed5141d767597081ea1dc97a2469 + pristine_git_object: 5bf9b60d1b211bd36ad7e144d2fcdb12f2a55ecc + docs/operations/createoauthtokenrequest.mdx: + id: d201ddca0ef0 + last_write_checksum: sha1:c746d2013cc07e26d9dae35ca1af588b47dd69d4 + pristine_git_object: ce9fcd9ae5274fa03b5cf428a42bdc08cbfd064d docs/operations/createobservabilitydestinationglobals.mdx: id: de09999b6578 last_write_checksum: sha1:3f7f4167ab7c14d54bac74001d241091abbb5939 @@ -6928,6 +7000,14 @@ trackedFiles: id: fa5ad15aebfd last_write_checksum: sha1:daa5aafeecb31a35e7cb1bbedc70b722f6a675a5 pristine_git_object: c7dbff35b7c3345c54c268f81a8ad4dac24cc5c3 + docs/operations/listoauthjwksglobals.mdx: + id: 7fe931762b70 + last_write_checksum: sha1:5d1a1236488c46dc129a264b6df22e5842921611 + pristine_git_object: 17a2b2df2642d1309c149f226484a740c68c97e7 + docs/operations/listoauthjwksrequest.mdx: + id: 4f7bdb101f79 + last_write_checksum: sha1:7e9e6ef9c3d544ef17d7fe0549027c40f9b7e2c0 + pristine_git_object: b0535221aa613a9576565f377a39bed881c8b270 docs/operations/listobservabilitydestinationsglobals.mdx: id: 3a51e19188e6 last_write_checksum: sha1:fa7e365b06c4bdfcd6af99c72d23c4c63218e7bb @@ -7422,8 +7502,8 @@ trackedFiles: pristine_git_object: 704be1ed3f77b0ee75b738939864833e1cb52a2e docs/sdks/oauth/README.mdx: id: 42b5079343d2 - last_write_checksum: sha1:96e141747d42bc814cafc4c3508760554a9bf410 - pristine_git_object: 499c17463c6b6f3b72c922c4a39fdff027d0a851 + last_write_checksum: sha1:e58bac6bbe1c443462510a1dc5dca91bb4996525 + pristine_git_object: 5e90344f13d6f49aa9399a4fd6bc2b870b54d348 docs/sdks/observability/README.mdx: id: 75811527e651 last_write_checksum: sha1:8dcbcdd3a6ec358ebafd8246f0bf7bf9071c2967 @@ -7474,8 +7554,8 @@ trackedFiles: pristine_git_object: 3e38f1a929f7d6b1d6de74604aa87e3d8f010544 pyproject.toml: id: 5d07e7d72637 - last_write_checksum: sha1:6a93cfc0b9d57daad29477ac565b9c8bd5099095 - pristine_git_object: 2f994cca195bb80c8deb3ba9cb82c17f96688013 + last_write_checksum: sha1:56fe290e2eb62505ca606a14870c251c65b397b4 + pristine_git_object: c888733edb984115721da78647439d9a37fcfe0c scripts/prepare_readme.py: id: e0c5957a6035 last_write_checksum: sha1:77f44b60b98bc126557ec27391f91dfba764bb54 @@ -7502,8 +7582,8 @@ trackedFiles: pristine_git_object: 86713cfea633e09d33b3d4e65281071fe20e6137 src/openrouter/_version.py: id: d8d15ad6c586 - last_write_checksum: sha1:12e4c32845fc1bd5033e126961ba5276b4f4961e - pristine_git_object: be165943041ea357cd2c73da716dc984f2050f6f + last_write_checksum: sha1:809e487597022e0800957114a0be4210261a4b0b + pristine_git_object: 18a2bfe926c463cdfe989b6b03d57298076e5291 src/openrouter/analytics.py: id: cb406b5aaabb last_write_checksum: sha1:1e0004d8d1d5d797e2b54cd1cabeb7f9489d08e9 @@ -7542,8 +7622,8 @@ trackedFiles: pristine_git_object: ad3d247954547814054c01989a2dff3d12b3e4e1 src/openrouter/components/__init__.py: id: 81754e97b3f4 - last_write_checksum: sha1:9407e2d53ca342ebec61ba62a021df466d857e9f - pristine_git_object: 387c9d06176293810c2b3368f291c5d917f4c96a + last_write_checksum: sha1:1cf6c72ab08bb8e0d913cff224c6c960be606877 + pristine_git_object: 18024225c70341bc7c9c24257ec87b91751ec68c src/openrouter/components/aabenchmarkentry.py: id: e2e0f0b48c82 last_write_checksum: sha1:fab4d9a24d2cea937bb749d46c5f83941e99d65c @@ -8952,6 +9032,14 @@ trackedFiles: id: 6ebceef7a039 last_write_checksum: sha1:bc01cbf5e3da855698de435b270930b4087377fe pristine_git_object: 7f9b6c70ef10b154e67db68ce62b326ab629cde8 + src/openrouter/components/oautherrorresponse.py: + id: d1da65a1b9e9 + last_write_checksum: sha1:2446d9597c040191136f9ab3633f3919caa88369 + pristine_git_object: 6951a0dad7127c772adca63fd31a8d24738129e1 + src/openrouter/components/oauthjwks.py: + id: 3d1408a70c14 + last_write_checksum: sha1:d6e7272f71828ba8b3feeff3a0ba35ee5fd6a1e4 + pristine_git_object: 17e5e3520b488409523771b3af22cdd7947b8aa1 src/openrouter/components/observabilityarizedestination.py: id: 8926882c1d18 last_write_checksum: sha1:a85ef87c067e35b9523ff45a6fe9e41b88261c4e @@ -9796,6 +9884,14 @@ trackedFiles: id: 150a449e46de last_write_checksum: sha1:56b0dc5aaacd994dfa1f16900a4fe1b4eea2f222 pristine_git_object: ffae73647f1060eeb9f46a4d331de6b9760dc5d9 + src/openrouter/components/tokenexchangerequest.py: + id: 2359476f8b4b + last_write_checksum: sha1:c93ebac5a861d46802866df990dd9bffd7c2a8dc + pristine_git_object: a29bf1760577ba7958a3f98bf0a95c27fbd18592 + src/openrouter/components/tokenexchangeresponse.py: + id: c7c8ecb676b8 + last_write_checksum: sha1:bd1d4f0bbb4c320e630e28f92504f040c927eabf + pristine_git_object: ce7b2081d390b2e9c986f61c9d1be50ab6e5794f src/openrouter/components/toolcallstatus.py: id: 32339139c3f3 last_write_checksum: sha1:a75631cdb460f190aa10d5557519519d1ef5fbe3 @@ -10062,8 +10158,8 @@ trackedFiles: pristine_git_object: 5c3a48759ba31aa633627707b68885b6cc367ddf src/openrouter/errors/__init__.py: id: 366154d0d60a - last_write_checksum: sha1:6d4e463d60596f3eaf527d5ae08577a3b17337bf - pristine_git_object: cfe7cbb6a75e5b5eb3b25b630ca206f5654d6742 + last_write_checksum: sha1:341868aa0a77c47442fdc2c1beb62f24cc756477 + pristine_git_object: 10a1c8cff01dd919032918f50b3e3478c042e2b5 src/openrouter/errors/badgatewayresponse_error.py: id: 818c3605ce23 last_write_checksum: sha1:f0307bff4a47f950c514d7d47de5690cac871bbb @@ -10096,6 +10192,10 @@ trackedFiles: id: 283f4657fb1c last_write_checksum: sha1:60f44e79ac40d4c8ffaee143588ea288745c9a42 pristine_git_object: 2de2d02103bb5ecac80c2c4667eadb70b7d931c4 + src/openrouter/errors/oautherrorresponse.py: + id: 0de21e8a0df4 + last_write_checksum: sha1:cd16f8154c1c4e655c7586de303e49372378527a + pristine_git_object: f242940015e81046dc47316ad54cbaa3f873ee0b src/openrouter/errors/openrouterdefaulterror.py: id: ec1269b0a602 last_write_checksum: sha1:c7e323985411ebc622a365df7d1560db134e5fb8 @@ -10178,16 +10278,16 @@ trackedFiles: pristine_git_object: b4576cd59564f3ea17fd4cba053913c13b8f3d70 src/openrouter/oauth.py: id: 1948ce27255b - last_write_checksum: sha1:32e42219a709e449c5cc418d535a9900ae6fd0c8 - pristine_git_object: 469011d79d90ecc0e555f745a12f248dda78688a + last_write_checksum: sha1:7e9fc1853f0c0a8116436bc9b850e848a661ecf8 + pristine_git_object: 67a8110158546a5f1ea311e63ef8d5fc1837f70b src/openrouter/observability.py: id: 6a17f32d3f33 last_write_checksum: sha1:cfa8495534fa7d219e42cc4a2425417738279b85 pristine_git_object: 5c553b76ab24d9eaef51c3bf6d85aa74391e335e src/openrouter/operations/__init__.py: id: 9afcea1e7161 - last_write_checksum: sha1:485909820533419acf0fa1d0c8fef5acfe16bee5 - pristine_git_object: 153455463a5dffde89e5d15bc223e3aa091d4eb7 + last_write_checksum: sha1:1c4c409bc631b080407fcf9977af36eedab52a87 + pristine_git_object: b76c802abec1ef1bb8fa2625772374243d75f281 src/openrouter/operations/bulkaddworkspacemembers.py: id: e0ed56117619 last_write_checksum: sha1:5c44eb0d40fdece3ac084615f6c6082be4cf1d5a @@ -10248,6 +10348,10 @@ trackedFiles: id: 64ad31fdaa6c last_write_checksum: sha1:146edc8153a6ee74f1b8a6cdbd2a6c91733f11d8 pristine_git_object: 510645f76bbdcc2a8f754f5527d14ae3d0a5a16c + src/openrouter/operations/createoauthtoken.py: + id: 02e1c061780d + last_write_checksum: sha1:006884cfeeecfede1434f194460b7189cae89de1 + pristine_git_object: 6c66e0417bea8fda22ff93ad7f24bdb03f445584 src/openrouter/operations/createobservabilitydestination.py: id: ce29c303fb0d last_write_checksum: sha1:b9dfa5198721adbca45f48b7fb632bee09780fff @@ -10492,6 +10596,10 @@ trackedFiles: id: 16eb5946cf60 last_write_checksum: sha1:7cdc18f6096cadeb9fe60e9eec6fdf03fc5b511b pristine_git_object: 78a9304b8224bad72de2143aa4dd3d52e6604cc1 + src/openrouter/operations/listoauthjwks.py: + id: 329ac9d6fa76 + last_write_checksum: sha1:8d6b08b6637a0ff49f88313a9f1bed03349655f1 + pristine_git_object: f79a46a1130d3dec736b61fcc995776941b6d918 src/openrouter/operations/listobservabilitydestinations.py: id: 40d2ffa975ee last_write_checksum: sha1:81c37a18a7326ddbe95a22d2f43a178cd6a58a93 @@ -12584,5 +12692,26 @@ examples: application/json: {"error": {"code": 500, "message": "Internal Server Error"}} "503": application/json: {"error": {"code": 503, "message": "Service temporarily unavailable"}} + listOauthJwks: + speakeasy-default-list-oauth-jwks: + responses: + "200": + application/json: {"keys": [{"alg": "ES256", "crv": "P-256", "kid": "or-2026-09", "kty": "EC", "use": "sig", "x": "f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU", "y": "x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0"}]} + "500": + application/json: {"error": {"code": 500, "message": "Internal Server Error"}} + createOauthToken: + speakeasy-default-create-oauth-token: + requestBody: + application/x-www-form-urlencoded: {"federation_policy_id": "4b2f7d1e-8c3a-4e5f-9a6b-1c2d3e4f5a6b", "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange", "subject_token": "", "subject_token_type": "urn:ietf:params:oauth:token-type:jwt"} + responses: + "200": + application/json: {"access_token": "", "expires_in": 900, "issued_token_type": "urn:ietf:params:oauth:token-type:access_token", "scope": "inference", "token_type": "Bearer"} + "400": + application/json: {"error": "invalid_grant", "error_description": "The subject token was not accepted."} + "500": + application/json: {"error": "invalid_grant", "error_description": "The subject token was not accepted."} examplesVersion: 1.0.2 -releaseNotes: "## Python SDK Changes:\n* `open_router.guardrails.list()`: `response.data[].allowed_data_regions` **Added**\n* `open_router.guardrails.create()`: \n * `request.allowed_data_regions` **Added**\n * `response.data.allowed_data_regions` **Added**\n* `open_router.guardrails.get()`: `response.data.allowed_data_regions` **Added**\n* `open_router.guardrails.update()`: \n * `request.allowed_data_regions` **Added**\n * `response.data.allowed_data_regions` **Added**\n" +releaseNotes: | + ## Python SDK Changes: + * `open_router.o_auth.list_oauth_jwks()`: **Added** + * `open_router.o_auth.create_oauth_token()`: **Added** diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml index 43145786..81ab11dd 100644 --- a/.speakeasy/gen.yaml +++ b/.speakeasy/gen.yaml @@ -36,7 +36,7 @@ generation: documentation: mintlify preApplyUnionDiscriminators: true python: - version: 1.1.118 + version: 1.1.119 additionalDependencies: dev: {} main: {} diff --git a/.speakeasy/out.openapi.yaml b/.speakeasy/out.openapi.yaml index 2aaa8d33..ca3868cf 100644 --- a/.speakeasy/out.openapi.yaml +++ b/.speakeasy/out.openapi.yaml @@ -15088,6 +15088,83 @@ components: - 'code' - 'message' type: 'object' + OAuthErrorResponse: + description: 'RFC 6749 §5.2 error response.' + example: + error: 'invalid_grant' + error_description: 'The subject token was not accepted.' + properties: + error: + enum: + - 'invalid_request' + - 'invalid_grant' + - 'unsupported_grant_type' + - 'invalid_scope' + - 'server_error' + - 'temporarily_unavailable' + type: 'string' + x-speakeasy-unknown-values: allow + error_description: + type: 'string' + required: + - 'error' + - 'error_description' + type: 'object' + OAuthJwks: + description: 'RFC 7517 JWK Set of the keys OpenRouter signs access tokens with.' + example: + keys: + - alg: 'ES256' + crv: 'P-256' + kid: 'or-2026-09' + kty: 'EC' + use: 'sig' + x: 'f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU' + 'y': 'x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0' + properties: + keys: + items: + additionalProperties: false + properties: + alg: + enum: + - 'ES256' + type: 'string' + crv: + enum: + - 'P-256' + type: 'string' + kid: + minLength: 1 + type: 'string' + kty: + enum: + - 'EC' + type: 'string' + use: + enum: + - 'sig' + type: 'string' + x: + pattern: '^[A-Za-z0-9_-]+$' + type: 'string' + 'y': + pattern: '^[A-Za-z0-9_-]+$' + type: 'string' + required: + - 'kty' + - 'crv' + - 'kid' + - 'x' + - 'y' + - 'alg' + - 'use' + type: 'object' + minItems: 1 + type: 'array' + required: + - 'keys' + type: 'object' ObservabilityArizeDestination: example: api_key_hashes: null @@ -25122,6 +25199,92 @@ components: example: format: type: 'text' + TokenExchangeRequest: + description: 'RFC 8693 token exchange request body (application/x-www-form-urlencoded).' + example: + federation_policy_id: '4b2f7d1e-8c3a-4e5f-9a6b-1c2d3e4f5a6b' + grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange' + subject_token: '' + subject_token_type: 'urn:ietf:params:oauth:token-type:jwt' + properties: + federation_policy_id: + description: 'The federation policy to evaluate, from Settings → Workload identity. Binds the exchange to one organization.' + example: '4b2f7d1e-8c3a-4e5f-9a6b-1c2d3e4f5a6b' + format: 'uuid' + type: 'string' + grant_type: + description: 'Must be `urn:ietf:params:oauth:grant-type:token-exchange`.' + enum: + - 'urn:ietf:params:oauth:grant-type:token-exchange' + example: 'urn:ietf:params:oauth:grant-type:token-exchange' + type: 'string' + requested_token_type: + description: 'Optional; when present must be `urn:ietf:params:oauth:token-type:access_token`.' + enum: + - 'urn:ietf:params:oauth:token-type:access_token' + example: 'urn:ietf:params:oauth:token-type:access_token' + type: 'string' + scope: + description: 'Optional; only `inference` is available.' + enum: + - 'inference' + example: 'inference' + type: 'string' + subject_token: + description: 'The JWT issued by your identity provider.' + example: '' + maxLength: 16384 + minLength: 1 + type: 'string' + subject_token_type: + description: 'Must be `urn:ietf:params:oauth:token-type:jwt`.' + enum: + - 'urn:ietf:params:oauth:token-type:jwt' + example: 'urn:ietf:params:oauth:token-type:jwt' + type: 'string' + required: + - 'grant_type' + - 'subject_token' + - 'federation_policy_id' + - 'subject_token_type' + type: 'object' + TokenExchangeResponse: + description: 'RFC 8693 token exchange response.' + example: + access_token: '' + expires_in: 900 + issued_token_type: 'urn:ietf:params:oauth:token-type:access_token' + scope: 'inference' + token_type: 'Bearer' + properties: + access_token: + description: 'A short-lived JWT to send as `Authorization: Bearer` to the inference API.' + example: '' + type: 'string' + expires_in: + description: 'Seconds until the access token expires: at most 15 minutes, and never later than the subject token expires.' + example: 900 + type: 'integer' + issued_token_type: + enum: + - 'urn:ietf:params:oauth:token-type:access_token' + example: 'urn:ietf:params:oauth:token-type:access_token' + type: 'string' + scope: + example: 'inference' + type: 'string' + token_type: + enum: + - 'Bearer' + example: 'Bearer' + type: 'string' + required: + - 'access_token' + - 'issued_token_type' + - 'token_type' + - 'expires_in' + - 'scope' + type: 'object' ToolCallStatus: enum: - 'in_progress' @@ -36621,6 +36784,78 @@ paths: - $ref: "#/components/parameters/AppIdentifier" - $ref: "#/components/parameters/AppDisplayName" - $ref: "#/components/parameters/AppCategories" + /oauth/jwks: + get: + description: 'RFC 7517 JWK Set containing the public keys OpenRouter signs access tokens with.' + operationId: 'listOauthJwks' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/OAuthJwks' + description: 'JWK Set' + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/InternalServerResponse' + description: 'Signing keys are not configured' + summary: 'OpenRouter access token signing keys' + tags: + - 'OAuth' + parameters: + - $ref: "#/components/parameters/AppIdentifier" + - $ref: "#/components/parameters/AppDisplayName" + - $ref: "#/components/parameters/AppCategories" + /oauth/token: + post: + description: 'RFC 8693 token exchange. Presents a JWT from an issuer your organization trusts (Settings → Workload identity) and receives a short-lived OpenRouter access token that acts as the API key the matching federation policy targets.' + operationId: 'createOauthToken' + requestBody: + content: + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/TokenExchangeRequest' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/TokenExchangeResponse' + description: 'Access token issued' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/OAuthErrorResponse' + description: 'Malformed request, unsupported grant, or the subject token was not accepted' + '429': + content: + application/json: + schema: + $ref: '#/components/schemas/OAuthErrorResponse' + description: 'Rate limited' + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/OAuthErrorResponse' + description: 'The token could not be issued' + '503': + content: + application/json: + schema: + $ref: '#/components/schemas/OAuthErrorResponse' + description: 'The issuer’s discovery document or JWKS could not be fetched' + summary: 'Exchange a workload identity token' + tags: + - 'OAuth' + parameters: + - $ref: "#/components/parameters/AppIdentifier" + - $ref: "#/components/parameters/AppDisplayName" + - $ref: "#/components/parameters/AppCategories" /observability/destinations: get: description: 'List the observability destinations configured for the authenticated entity''s default workspace. Use the `workspace_id` query parameter to scope the result to a different workspace. Only destinations with stable release status are surfaced — destinations of other types are excluded. [Management key](/docs/guides/overview/auth/management-api-keys) required.' diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock index f3135b94..c5d81444 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:7653bb5ddb5a2631fbafe215ee7a9cff39561fd3d4aac78269142fe5e9480f59 - sourceBlobDigest: sha256:aa2090dae19b80edae917cc47934cfa0551033bb2e0e7f3900bebc99bf220cef + sourceRevisionDigest: sha256:548d52c5c213dc69da9a5075de144d2d234ae4a761b51515b9fb197d414e23b7 + sourceBlobDigest: sha256:6f8a3a2bf9e6a014f1c0fe5e85415d4ba182afa6a3fadd5224480bf80f10bc51 tags: - latest - 1.0.0 @@ -11,10 +11,10 @@ targets: open-router: source: OpenRouter API sourceNamespace: open-router-chat-completions-api - sourceRevisionDigest: sha256:7653bb5ddb5a2631fbafe215ee7a9cff39561fd3d4aac78269142fe5e9480f59 - sourceBlobDigest: sha256:aa2090dae19b80edae917cc47934cfa0551033bb2e0e7f3900bebc99bf220cef + sourceRevisionDigest: sha256:548d52c5c213dc69da9a5075de144d2d234ae4a761b51515b9fb197d414e23b7 + sourceBlobDigest: sha256:6f8a3a2bf9e6a014f1c0fe5e85415d4ba182afa6a3fadd5224480bf80f10bc51 codeSamplesNamespace: open-router-python-code-samples - codeSamplesRevisionDigest: sha256:4b44a31a05c14148f404504d497c148f0655682a8c6cd97a71d3ca6879fccbc0 + codeSamplesRevisionDigest: sha256:b1caf408f8f4dbb6d7b94fb09bb1cc248275f7f241a09146682d20efe1e299b6 workflow: workflowVersion: 1.0.0 speakeasyVersion: 1.787.0 diff --git a/RELEASES.md b/RELEASES.md index b08eb8ec..c876fe36 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1969,4 +1969,14 @@ Based on: ### Generated - [python v1.1.118] . ### Releases -- [PyPI v1.1.118] https://pypi.org/project/openrouter/1.1.118 - . \ No newline at end of file +- [PyPI v1.1.118] https://pypi.org/project/openrouter/1.1.118 - . + +## 2026-09-03 00:26:00 +### Changes +Based on: +- OpenAPI Doc +- Speakeasy CLI 1.787.0 (2.914.0) https://github.com/speakeasy-api/speakeasy +### Generated +- [python v1.1.119] . +### Releases +- [PyPI v1.1.119] https://pypi.org/project/openrouter/1.1.119 - . \ No newline at end of file diff --git a/docs/components/alg.mdx b/docs/components/alg.mdx new file mode 100644 index 00000000..40fd3236 --- /dev/null +++ b/docs/components/alg.mdx @@ -0,0 +1,15 @@ +--- +title: "Alg" +--- + +## Example Usage + +```python +from openrouter.components import Alg +value: Alg = "ES256" +``` + + +## Values + +- `"ES256"` diff --git a/docs/components/crv.mdx b/docs/components/crv.mdx new file mode 100644 index 00000000..51643386 --- /dev/null +++ b/docs/components/crv.mdx @@ -0,0 +1,15 @@ +--- +title: "Crv" +--- + +## Example Usage + +```python +from openrouter.components import Crv +value: Crv = "P-256" +``` + + +## Values + +- `"P-256"` diff --git a/docs/components/errorenum.mdx b/docs/components/errorenum.mdx new file mode 100644 index 00000000..95a2d3dc --- /dev/null +++ b/docs/components/errorenum.mdx @@ -0,0 +1,24 @@ +--- +title: "ErrorEnum" +--- + +## Example Usage + +```python +from openrouter.components import ErrorEnum + +# Open enum: unrecognized values are captured as UnrecognizedStr +value: ErrorEnum = "invalid_request" +``` + + +## Values + +This is an open enum. Unrecognized values will not fail type checks. + +- `"invalid_request"` +- `"invalid_grant"` +- `"unsupported_grant_type"` +- `"invalid_scope"` +- `"server_error"` +- `"temporarily_unavailable"` diff --git a/docs/components/granttype.mdx b/docs/components/granttype.mdx new file mode 100644 index 00000000..6e17644d --- /dev/null +++ b/docs/components/granttype.mdx @@ -0,0 +1,17 @@ +--- +title: "GrantType" +--- + +Must be `urn:ietf:params:oauth:grant-type:token-exchange`. + +## Example Usage + +```python +from openrouter.components import GrantType +value: GrantType = "urn:ietf:params:oauth:grant-type:token-exchange" +``` + + +## Values + +- `"urn:ietf:params:oauth:grant-type:token-exchange"` diff --git a/docs/components/issuedtokentype.mdx b/docs/components/issuedtokentype.mdx new file mode 100644 index 00000000..cca4300f --- /dev/null +++ b/docs/components/issuedtokentype.mdx @@ -0,0 +1,15 @@ +--- +title: "IssuedTokenType" +--- + +## Example Usage + +```python +from openrouter.components import IssuedTokenType +value: IssuedTokenType = "urn:ietf:params:oauth:token-type:access_token" +``` + + +## Values + +- `"urn:ietf:params:oauth:token-type:access_token"` diff --git a/docs/components/key.mdx b/docs/components/key.mdx new file mode 100644 index 00000000..48c2e083 --- /dev/null +++ b/docs/components/key.mdx @@ -0,0 +1,15 @@ +--- +title: "Key" +--- + +## Fields + +| Field | Type | Required | Description | +| -------------------------------------- | -------------------------------------- | -------------------------------------- | -------------------------------------- | +| `alg` | [components.Alg](../components/alg.mdx) | :heavy_check_mark: | N/A | +| `crv` | [components.Crv](../components/crv.mdx) | :heavy_check_mark: | N/A | +| `kid` | *str* | :heavy_check_mark: | N/A | +| `kty` | [components.Kty](../components/kty.mdx) | :heavy_check_mark: | N/A | +| `use` | [components.Use](../components/use.mdx) | :heavy_check_mark: | N/A | +| `x` | *str* | :heavy_check_mark: | N/A | +| `y` | *str* | :heavy_check_mark: | N/A | \ No newline at end of file diff --git a/docs/components/kty.mdx b/docs/components/kty.mdx new file mode 100644 index 00000000..bfef4620 --- /dev/null +++ b/docs/components/kty.mdx @@ -0,0 +1,15 @@ +--- +title: "Kty" +--- + +## Example Usage + +```python +from openrouter.components import Kty +value: Kty = "EC" +``` + + +## Values + +- `"EC"` diff --git a/docs/components/oauthjwks.mdx b/docs/components/oauthjwks.mdx new file mode 100644 index 00000000..463ee9cd --- /dev/null +++ b/docs/components/oauthjwks.mdx @@ -0,0 +1,12 @@ +--- +title: "OAuthJwks" +--- + +RFC 7517 JWK Set of the keys OpenRouter signs access tokens with. + + +## Fields + +| Field | Type | Required | Description | +| -------------------------------------------- | -------------------------------------------- | -------------------------------------------- | -------------------------------------------- | +| `keys` | List[[components.Key](../components/key.mdx)] | :heavy_check_mark: | N/A | \ No newline at end of file diff --git a/docs/components/requestedtokentype.mdx b/docs/components/requestedtokentype.mdx new file mode 100644 index 00000000..1994454b --- /dev/null +++ b/docs/components/requestedtokentype.mdx @@ -0,0 +1,17 @@ +--- +title: "RequestedTokenType" +--- + +Optional; when present must be `urn:ietf:params:oauth:token-type:access_token`. + +## Example Usage + +```python +from openrouter.components import RequestedTokenType +value: RequestedTokenType = "urn:ietf:params:oauth:token-type:access_token" +``` + + +## Values + +- `"urn:ietf:params:oauth:token-type:access_token"` diff --git a/docs/components/scope.mdx b/docs/components/scope.mdx new file mode 100644 index 00000000..ca4b238c --- /dev/null +++ b/docs/components/scope.mdx @@ -0,0 +1,17 @@ +--- +title: "Scope" +--- + +Optional; only `inference` is available. + +## Example Usage + +```python +from openrouter.components import Scope +value: Scope = "inference" +``` + + +## Values + +- `"inference"` diff --git a/docs/components/subjecttokentype.mdx b/docs/components/subjecttokentype.mdx new file mode 100644 index 00000000..3e6f988e --- /dev/null +++ b/docs/components/subjecttokentype.mdx @@ -0,0 +1,17 @@ +--- +title: "SubjectTokenType" +--- + +Must be `urn:ietf:params:oauth:token-type:jwt`. + +## Example Usage + +```python +from openrouter.components import SubjectTokenType +value: SubjectTokenType = "urn:ietf:params:oauth:token-type:jwt" +``` + + +## Values + +- `"urn:ietf:params:oauth:token-type:jwt"` diff --git a/docs/components/tokenexchangerequest.mdx b/docs/components/tokenexchangerequest.mdx new file mode 100644 index 00000000..84a147af --- /dev/null +++ b/docs/components/tokenexchangerequest.mdx @@ -0,0 +1,17 @@ +--- +title: "TokenExchangeRequest" +--- + +RFC 8693 token exchange request body (application/x-www-form-urlencoded). + + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | +| `federation_policy_id` | *str* | :heavy_check_mark: | The federation policy to evaluate, from Settings → Workload identity. Binds the exchange to one organization. | 4b2f7d1e-8c3a-4e5f-9a6b-1c2d3e4f5a6b | +| `grant_type` | [components.GrantType](../components/granttype.mdx) | :heavy_check_mark: | Must be `urn:ietf:params:oauth:grant-type:token-exchange`. | urn:ietf:params:oauth:grant-type:token-exchange | +| `requested_token_type` | [Optional[components.RequestedTokenType]](../components/requestedtokentype.mdx) | :heavy_minus_sign: | Optional; when present must be `urn:ietf:params:oauth:token-type:access_token`. | urn:ietf:params:oauth:token-type:access_token | +| `scope` | [Optional[components.Scope]](../components/scope.mdx) | :heavy_minus_sign: | Optional; only `inference` is available. | inference | +| `subject_token` | *str* | :heavy_check_mark: | The JWT issued by your identity provider. | \ | +| `subject_token_type` | [components.SubjectTokenType](../components/subjecttokentype.mdx) | :heavy_check_mark: | Must be `urn:ietf:params:oauth:token-type:jwt`. | urn:ietf:params:oauth:token-type:jwt | \ No newline at end of file diff --git a/docs/components/tokenexchangeresponse.mdx b/docs/components/tokenexchangeresponse.mdx new file mode 100644 index 00000000..c3a8de52 --- /dev/null +++ b/docs/components/tokenexchangeresponse.mdx @@ -0,0 +1,16 @@ +--- +title: "TokenExchangeResponse" +--- + +RFC 8693 token exchange response. + + +## Fields + +| Field | Type | Required | Description | Example | +| ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | +| `access_token` | *str* | :heavy_check_mark: | A short-lived JWT to send as `Authorization: Bearer` to the inference API. | \ | +| `expires_in` | *int* | :heavy_check_mark: | Seconds until the access token expires: at most 15 minutes, and never later than the subject token expires. | 900 | +| `issued_token_type` | [components.IssuedTokenType](../components/issuedtokentype.mdx) | :heavy_check_mark: | N/A | urn:ietf:params:oauth:token-type:access_token | +| `scope` | *str* | :heavy_check_mark: | N/A | inference | +| `token_type` | [components.TokenType](../components/tokentype.mdx) | :heavy_check_mark: | N/A | Bearer | \ No newline at end of file diff --git a/docs/components/tokentype.mdx b/docs/components/tokentype.mdx new file mode 100644 index 00000000..31766573 --- /dev/null +++ b/docs/components/tokentype.mdx @@ -0,0 +1,15 @@ +--- +title: "TokenType" +--- + +## Example Usage + +```python +from openrouter.components import TokenType +value: TokenType = "Bearer" +``` + + +## Values + +- `"Bearer"` diff --git a/docs/components/use.mdx b/docs/components/use.mdx new file mode 100644 index 00000000..4590a4bc --- /dev/null +++ b/docs/components/use.mdx @@ -0,0 +1,15 @@ +--- +title: "Use" +--- + +## Example Usage + +```python +from openrouter.components import Use +value: Use = "sig" +``` + + +## Values + +- `"sig"` diff --git a/docs/errors/oautherrorresponse.mdx b/docs/errors/oautherrorresponse.mdx new file mode 100644 index 00000000..9d163168 --- /dev/null +++ b/docs/errors/oautherrorresponse.mdx @@ -0,0 +1,13 @@ +--- +title: "OAuthErrorResponse" +--- + +RFC 6749 §5.2 error response. + + +## Fields + +| Field | Type | Required | Description | +| -------------------------------------------------- | -------------------------------------------------- | -------------------------------------------------- | -------------------------------------------------- | +| `error` | [components.ErrorEnum](../components/errorenum.mdx) | :heavy_check_mark: | N/A | +| `error_description` | *str* | :heavy_check_mark: | N/A | \ No newline at end of file diff --git a/docs/operations/createoauthtokenglobals.mdx b/docs/operations/createoauthtokenglobals.mdx new file mode 100644 index 00000000..5bf9b60d --- /dev/null +++ b/docs/operations/createoauthtokenglobals.mdx @@ -0,0 +1,11 @@ +--- +title: "CreateOauthTokenGlobals" +--- + +## 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/createoauthtokenrequest.mdx b/docs/operations/createoauthtokenrequest.mdx new file mode 100644 index 00000000..ce9fcd9a --- /dev/null +++ b/docs/operations/createoauthtokenrequest.mdx @@ -0,0 +1,12 @@ +--- +title: "CreateOauthTokenRequest" +--- + +## 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.
| | +| `token_exchange_request` | [components.TokenExchangeRequest](../components/tokenexchangerequest.mdx) | :heavy_check_mark: | N/A | \{
"federation_policy_id": "4b2f7d1e-8c3a-4e5f-9a6b-1c2d3e4f5a6b",
"grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
"subject_token": "\u003cjwt from your identity provider\u003e",
"subject_token_type": "urn:ietf:params:oauth:token-type:jwt"
} | \ No newline at end of file diff --git a/docs/operations/listoauthjwksglobals.mdx b/docs/operations/listoauthjwksglobals.mdx new file mode 100644 index 00000000..17a2b2df --- /dev/null +++ b/docs/operations/listoauthjwksglobals.mdx @@ -0,0 +1,11 @@ +--- +title: "ListOauthJwksGlobals" +--- + +## 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/listoauthjwksrequest.mdx b/docs/operations/listoauthjwksrequest.mdx new file mode 100644 index 00000000..b0535221 --- /dev/null +++ b/docs/operations/listoauthjwksrequest.mdx @@ -0,0 +1,11 @@ +--- +title: "ListOauthJwksRequest" +--- + +## 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/sdks/oauth/README.mdx b/docs/sdks/oauth/README.mdx index 499c1746..5e90344f 100644 --- a/docs/sdks/oauth/README.mdx +++ b/docs/sdks/oauth/README.mdx @@ -11,6 +11,8 @@ OAuth authentication endpoints * [exchange_auth_code_for_api_key](#exchange_auth_code_for_api_key) - Exchange authorization code for API key * [create_auth_code](#create_auth_code) - Create authorization code +* [list_oauth_jwks](#list_oauth_jwks) - OpenRouter access token signing keys +* [create_oauth_token](#create_oauth_token) - Exchange a workload identity token ## exchange_auth_code_for_api_key @@ -117,4 +119,101 @@ with OpenRouter( | errors.ForbiddenResponseError | 403 | application/json | | errors.ConflictResponseError | 409 | application/json | | errors.InternalServerResponseError | 500 | application/json | -| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | \ No newline at end of file +| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | + +## list_oauth_jwks + +RFC 7517 JWK Set containing the public keys OpenRouter signs access tokens with. + +### 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.o_auth.list_oauth_jwks() + + # Handle response + print(res) + +``` + +### Parameters + +| Parameter | 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.
| +| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.mdx) | :heavy_minus_sign: | Configuration to override the default retry behavior of the client. | + +### Response + +**[components.OAuthJwks](../../components/oauthjwks.mdx)** + +### Errors + +| Error Type | Status Code | Content Type | +| ---------------------------------- | ---------------------------------- | ---------------------------------- | +| errors.InternalServerResponseError | 500 | application/json | +| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | + +## create_oauth_token + +RFC 8693 token exchange. Presents a JWT from an issuer your organization trusts (Settings → Workload identity) and receives a short-lived OpenRouter access token that acts as the API key the matching federation policy targets. + +### 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.o_auth.create_oauth_token(federation_policy_id="4b2f7d1e-8c3a-4e5f-9a6b-1c2d3e4f5a6b", grant_type="urn:ietf:params:oauth:grant-type:token-exchange", subject_token="", subject_token_type="urn:ietf:params:oauth:token-type:jwt") + + # Handle response + print(res) + +``` + +### Parameters + +| Parameter | Type | Required | Description | Example | +| ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| `federation_policy_id` | *str* | :heavy_check_mark: | The federation policy to evaluate, from Settings → Workload identity. Binds the exchange to one organization. | 4b2f7d1e-8c3a-4e5f-9a6b-1c2d3e4f5a6b | +| `grant_type` | [components.GrantType](../../components/granttype.mdx) | :heavy_check_mark: | Must be `urn:ietf:params:oauth:grant-type:token-exchange`. | urn:ietf:params:oauth:grant-type:token-exchange | +| `subject_token` | *str* | :heavy_check_mark: | The JWT issued by your identity provider. | \ | +| `subject_token_type` | [components.SubjectTokenType](../../components/subjecttokentype.mdx) | :heavy_check_mark: | Must be `urn:ietf:params:oauth:token-type:jwt`. | urn:ietf:params:oauth:token-type:jwt | +| `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.
| | +| `requested_token_type` | [Optional[components.RequestedTokenType]](../../components/requestedtokentype.mdx) | :heavy_minus_sign: | Optional; when present must be `urn:ietf:params:oauth:token-type:access_token`. | urn:ietf:params:oauth:token-type:access_token | +| `scope` | [Optional[components.Scope]](../../components/scope.mdx) | :heavy_minus_sign: | Optional; only `inference` is available. | inference | +| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.mdx) | :heavy_minus_sign: | Configuration to override the default retry behavior of the client. | | + +### Response + +**[components.TokenExchangeResponse](../../components/tokenexchangeresponse.mdx)** + +### Errors + +| Error Type | Status Code | Content Type | +| ----------------------------- | ----------------------------- | ----------------------------- | +| errors.OAuthErrorResponse | 400, 429 | application/json | +| errors.OAuthErrorResponse | 500, 503 | application/json | +| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 2f994cca..c888733e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openrouter" -version = "1.1.118" +version = "1.1.119" 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 be165943..18a2bfe9 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.118" +__version__: str = "1.1.119" __openapi_doc_version__: str = "1.0.0" __gen_version__: str = "2.914.0" -__user_agent__: str = "speakeasy-sdk/python 1.1.118 2.914.0 1.0.0 openrouter" +__user_agent__: str = "speakeasy-sdk/python 1.1.119 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 387c9d06..18024225 100644 --- a/src/openrouter/components/__init__.py +++ b/src/openrouter/components/__init__.py @@ -1866,6 +1866,17 @@ NotFoundResponseErrorData, NotFoundResponseErrorDataTypedDict, ) + from .oautherrorresponse import ErrorEnum + from .oauthjwks import ( + Alg, + Crv, + Key, + KeyTypedDict, + Kty, + OAuthJwks, + OAuthJwksTypedDict, + Use, + ) from .observabilityarizedestination import ( ObservabilityArizeDestination, ObservabilityArizeDestinationConfig, @@ -2951,6 +2962,20 @@ TextExtendedConfigTypedDict, Verbosity, ) + from .tokenexchangerequest import ( + GrantType, + RequestedTokenType, + Scope, + SubjectTokenType, + TokenExchangeRequest, + TokenExchangeRequestTypedDict, + ) + from .tokenexchangeresponse import ( + IssuedTokenType, + TokenExchangeResponse, + TokenExchangeResponseTypedDict, + TokenType, + ) from .toolcallstatus import ToolCallStatus from .toolchoiceallowed import ( Mode, @@ -3249,6 +3274,7 @@ "AgentMessageItemTypeInputImage", "AgentMessageItemTypedDict", "AgentTypedDict", + "Alg", "AllowedCaller", "AllowedTools", "AllowedToolsTypedDict", @@ -3837,6 +3863,7 @@ "CreateWorkspaceRequestTypedDict", "CreateWorkspaceResponse", "CreateWorkspaceResponseTypedDict", + "Crv", "CustomTool", "CustomToolCallInputDeltaEvent", "CustomToolCallInputDeltaEventType", @@ -3933,6 +3960,7 @@ "EnumCapabilityTypedDict", "Environment", "ErrorCode", + "ErrorEnum", "ErrorEvent", "ErrorEventType", "ErrorEventTypedDict", @@ -4099,6 +4127,7 @@ "GetWorkspaceBudgetResponseTypedDict", "GetWorkspaceResponse", "GetWorkspaceResponseTypedDict", + "GrantType", "Guardrail", "GuardrailDataRegion", "GuardrailInterval", @@ -4278,6 +4307,7 @@ "InstructType", "InternalServerResponseErrorData", "InternalServerResponseErrorDataTypedDict", + "IssuedTokenType", "ItemReferenceItem", "ItemReferenceItemType", "ItemReferenceItemTypedDict", @@ -4287,8 +4317,11 @@ "KeepEnum", "KeepType", "KeepTypedDict", + "Key", "KeyAssignment", "KeyAssignmentTypedDict", + "KeyTypedDict", + "Kty", "LegacyChatContentVideo", "LegacyChatContentVideoInput", "LegacyChatContentVideoInputProcessing", @@ -4484,6 +4517,8 @@ "NeverTypedDict", "NotFoundResponseErrorData", "NotFoundResponseErrorDataTypedDict", + "OAuthJwks", + "OAuthJwksTypedDict", "ObservabilityArizeDestination", "ObservabilityArizeDestinationConfig", "ObservabilityArizeDestinationConfigTypedDict", @@ -5036,6 +5071,7 @@ "Region", "RequestTimeoutResponseErrorData", "RequestTimeoutResponseErrorDataTypedDict", + "RequestedTokenType", "RequireApproval", "RequireApprovalAlways", "RequireApprovalNever", @@ -5103,6 +5139,7 @@ "ScimGroupMappingRole", "ScimGroupMappingTypedDict", "ScimGroupTypedDict", + "Scope", "SearchContextSizeEnum", "SearchModelsServerToolConfig", "SearchModelsServerToolConfigTypedDict", @@ -5224,6 +5261,7 @@ "SubagentServerToolOpenRouter", "SubagentServerToolOpenRouterType", "SubagentServerToolOpenRouterTypedDict", + "SubjectTokenType", "SubmitGenerationFeedbackRequest", "SubmitGenerationFeedbackRequestTypedDict", "SubmitGenerationFeedbackResponse", @@ -5272,6 +5310,11 @@ "ThinkingTypedDict", "Timings", "TimingsTypedDict", + "TokenExchangeRequest", + "TokenExchangeRequestTypedDict", + "TokenExchangeResponse", + "TokenExchangeResponseTypedDict", + "TokenType", "TooManyRequestsResponseErrorData", "TooManyRequestsResponseErrorDataTypedDict", "ToolAdvisor20260301", @@ -5458,6 +5501,7 @@ "UsageCostDetails", "UsageCostDetailsTypedDict", "UsageTypedDict", + "Use", "UserLocation", "UserLocationTypedDict", "UtcDay", @@ -6918,6 +6962,15 @@ "UnknownNamespaceToolTool": ".namespacetool", "NotFoundResponseErrorData": ".notfoundresponseerrordata", "NotFoundResponseErrorDataTypedDict": ".notfoundresponseerrordata", + "ErrorEnum": ".oautherrorresponse", + "Alg": ".oauthjwks", + "Crv": ".oauthjwks", + "Key": ".oauthjwks", + "KeyTypedDict": ".oauthjwks", + "Kty": ".oauthjwks", + "OAuthJwks": ".oauthjwks", + "OAuthJwksTypedDict": ".oauthjwks", + "Use": ".oauthjwks", "ObservabilityArizeDestination": ".observabilityarizedestination", "ObservabilityArizeDestinationConfig": ".observabilityarizedestination", "ObservabilityArizeDestinationConfigTypedDict": ".observabilityarizedestination", @@ -7713,6 +7766,16 @@ "TextExtendedConfig": ".textextendedconfig", "TextExtendedConfigTypedDict": ".textextendedconfig", "Verbosity": ".textextendedconfig", + "GrantType": ".tokenexchangerequest", + "RequestedTokenType": ".tokenexchangerequest", + "Scope": ".tokenexchangerequest", + "SubjectTokenType": ".tokenexchangerequest", + "TokenExchangeRequest": ".tokenexchangerequest", + "TokenExchangeRequestTypedDict": ".tokenexchangerequest", + "IssuedTokenType": ".tokenexchangeresponse", + "TokenExchangeResponse": ".tokenexchangeresponse", + "TokenExchangeResponseTypedDict": ".tokenexchangeresponse", + "TokenType": ".tokenexchangeresponse", "ToolCallStatus": ".toolcallstatus", "Mode": ".toolchoiceallowed", "ModeAuto": ".toolchoiceallowed", diff --git a/src/openrouter/components/oautherrorresponse.py b/src/openrouter/components/oautherrorresponse.py new file mode 100644 index 00000000..6951a0da --- /dev/null +++ b/src/openrouter/components/oautherrorresponse.py @@ -0,0 +1,18 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +from __future__ import annotations +from openrouter.types import UnrecognizedStr +from typing import Literal, Union + + +ErrorEnum = Union[ + Literal[ + "invalid_request", + "invalid_grant", + "unsupported_grant_type", + "invalid_scope", + "server_error", + "temporarily_unavailable", + ], + UnrecognizedStr, +] diff --git a/src/openrouter/components/oauthjwks.py b/src/openrouter/components/oauthjwks.py new file mode 100644 index 00000000..17e5e352 --- /dev/null +++ b/src/openrouter/components/oauthjwks.py @@ -0,0 +1,56 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +from __future__ import annotations +from openrouter.types import BaseModel +from typing import List, Literal +from typing_extensions import TypedDict + + +Alg = Literal["ES256",] + + +Crv = Literal["P-256",] + + +Kty = Literal["EC",] + + +Use = Literal["sig",] + + +class KeyTypedDict(TypedDict): + alg: Alg + crv: Crv + kid: str + kty: Kty + use: Use + x: str + y: str + + +class Key(BaseModel): + alg: Alg + + crv: Crv + + kid: str + + kty: Kty + + use: Use + + x: str + + y: str + + +class OAuthJwksTypedDict(TypedDict): + r"""RFC 7517 JWK Set of the keys OpenRouter signs access tokens with.""" + + keys: List[KeyTypedDict] + + +class OAuthJwks(BaseModel): + r"""RFC 7517 JWK Set of the keys OpenRouter signs access tokens with.""" + + keys: List[Key] diff --git a/src/openrouter/components/tokenexchangerequest.py b/src/openrouter/components/tokenexchangerequest.py new file mode 100644 index 00000000..a29bf176 --- /dev/null +++ b/src/openrouter/components/tokenexchangerequest.py @@ -0,0 +1,81 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +from __future__ import annotations +from openrouter.types import BaseModel, UNSET_SENTINEL +from openrouter.utils import FieldMetadata +from pydantic import model_serializer +from typing import Literal, Optional +from typing_extensions import Annotated, NotRequired, TypedDict + + +GrantType = Literal["urn:ietf:params:oauth:grant-type:token-exchange",] +r"""Must be `urn:ietf:params:oauth:grant-type:token-exchange`.""" + + +RequestedTokenType = Literal["urn:ietf:params:oauth:token-type:access_token",] +r"""Optional; when present must be `urn:ietf:params:oauth:token-type:access_token`.""" + + +Scope = Literal["inference",] +r"""Optional; only `inference` is available.""" + + +SubjectTokenType = Literal["urn:ietf:params:oauth:token-type:jwt",] +r"""Must be `urn:ietf:params:oauth:token-type:jwt`.""" + + +class TokenExchangeRequestTypedDict(TypedDict): + r"""RFC 8693 token exchange request body (application/x-www-form-urlencoded).""" + + federation_policy_id: str + r"""The federation policy to evaluate, from Settings → Workload identity. Binds the exchange to one organization.""" + grant_type: GrantType + r"""Must be `urn:ietf:params:oauth:grant-type:token-exchange`.""" + subject_token: str + r"""The JWT issued by your identity provider.""" + subject_token_type: SubjectTokenType + r"""Must be `urn:ietf:params:oauth:token-type:jwt`.""" + requested_token_type: NotRequired[RequestedTokenType] + r"""Optional; when present must be `urn:ietf:params:oauth:token-type:access_token`.""" + scope: NotRequired[Scope] + r"""Optional; only `inference` is available.""" + + +class TokenExchangeRequest(BaseModel): + r"""RFC 8693 token exchange request body (application/x-www-form-urlencoded).""" + + federation_policy_id: Annotated[str, FieldMetadata(form=True)] + r"""The federation policy to evaluate, from Settings → Workload identity. Binds the exchange to one organization.""" + + grant_type: Annotated[GrantType, FieldMetadata(form=True)] + r"""Must be `urn:ietf:params:oauth:grant-type:token-exchange`.""" + + subject_token: Annotated[str, FieldMetadata(form=True)] + r"""The JWT issued by your identity provider.""" + + subject_token_type: Annotated[SubjectTokenType, FieldMetadata(form=True)] + r"""Must be `urn:ietf:params:oauth:token-type:jwt`.""" + + requested_token_type: Annotated[ + Optional[RequestedTokenType], FieldMetadata(form=True) + ] = None + r"""Optional; when present must be `urn:ietf:params:oauth:token-type:access_token`.""" + + scope: Annotated[Optional[Scope], FieldMetadata(form=True)] = None + r"""Optional; only `inference` is available.""" + + @model_serializer(mode="wrap") + def serialize_model(self, handler): + optional_fields = set(["requested_token_type", "scope"]) + 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/components/tokenexchangeresponse.py b/src/openrouter/components/tokenexchangeresponse.py new file mode 100644 index 00000000..ce7b2081 --- /dev/null +++ b/src/openrouter/components/tokenexchangeresponse.py @@ -0,0 +1,40 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +from __future__ import annotations +from openrouter.types import BaseModel +from typing import Literal +from typing_extensions import TypedDict + + +IssuedTokenType = Literal["urn:ietf:params:oauth:token-type:access_token",] + + +TokenType = Literal["Bearer",] + + +class TokenExchangeResponseTypedDict(TypedDict): + r"""RFC 8693 token exchange response.""" + + access_token: str + r"""A short-lived JWT to send as `Authorization: Bearer` to the inference API.""" + expires_in: int + r"""Seconds until the access token expires: at most 15 minutes, and never later than the subject token expires.""" + issued_token_type: IssuedTokenType + scope: str + token_type: TokenType + + +class TokenExchangeResponse(BaseModel): + r"""RFC 8693 token exchange response.""" + + access_token: str + r"""A short-lived JWT to send as `Authorization: Bearer` to the inference API.""" + + expires_in: int + r"""Seconds until the access token expires: at most 15 minutes, and never later than the subject token expires.""" + + issued_token_type: IssuedTokenType + + scope: str + + token_type: TokenType diff --git a/src/openrouter/errors/__init__.py b/src/openrouter/errors/__init__.py index cfe7cbb6..10a1c8cf 100644 --- a/src/openrouter/errors/__init__.py +++ b/src/openrouter/errors/__init__.py @@ -29,6 +29,7 @@ ) from .no_response_error import NoResponseError from .notfoundresponse_error import NotFoundResponseError, NotFoundResponseErrorData + from .oautherrorresponse import OAuthErrorResponse, OAuthErrorResponseData from .openrouterdefaulterror import OpenRouterDefaultError from .payloadtoolargeresponse_error import ( PayloadTooLargeResponseError, @@ -80,6 +81,8 @@ "NoResponseError", "NotFoundResponseError", "NotFoundResponseErrorData", + "OAuthErrorResponse", + "OAuthErrorResponseData", "OpenRouterDefaultError", "OpenRouterError", "PayloadTooLargeResponseError", @@ -117,6 +120,8 @@ "NoResponseError": ".no_response_error", "NotFoundResponseError": ".notfoundresponse_error", "NotFoundResponseErrorData": ".notfoundresponse_error", + "OAuthErrorResponse": ".oautherrorresponse", + "OAuthErrorResponseData": ".oautherrorresponse", "OpenRouterDefaultError": ".openrouterdefaulterror", "PayloadTooLargeResponseError": ".payloadtoolargeresponse_error", "PayloadTooLargeResponseErrorData": ".payloadtoolargeresponse_error", diff --git a/src/openrouter/errors/oautherrorresponse.py b/src/openrouter/errors/oautherrorresponse.py new file mode 100644 index 00000000..f2429400 --- /dev/null +++ b/src/openrouter/errors/oautherrorresponse.py @@ -0,0 +1,31 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +from __future__ import annotations +from dataclasses import dataclass, field +import httpx +from openrouter.components import oautherrorresponse as components_oautherrorresponse +from openrouter.errors import OpenRouterError +from openrouter.types import BaseModel +from typing import Optional + + +class OAuthErrorResponseData(BaseModel): + error: components_oautherrorresponse.ErrorEnum + error_description: str + + +@dataclass(unsafe_hash=True) +class OAuthErrorResponse(OpenRouterError): + r"""RFC 6749 §5.2 error response.""" + + data: OAuthErrorResponseData = field(hash=False) + + def __init__( + self, + data: OAuthErrorResponseData, + raw_response: httpx.Response, + body: Optional[str] = None, + ): + message = body or raw_response.text + super().__init__(message, raw_response, body) + object.__setattr__(self, "data", data) diff --git a/src/openrouter/oauth.py b/src/openrouter/oauth.py index 469011d7..67a81101 100644 --- a/src/openrouter/oauth.py +++ b/src/openrouter/oauth.py @@ -650,3 +650,527 @@ async def create_auth_code_async( ) raise errors.OpenRouterDefaultError("Unexpected response received", http_res) + + def list_oauth_jwks( + self, + *, + 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.OAuthJwks: + r"""OpenRouter access token signing keys + + RFC 7517 JWK Set containing the public keys OpenRouter signs access tokens with. + + :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.ListOauthJwksRequest( + http_referer=http_referer, + x_open_router_title=x_open_router_title, + x_open_router_categories=x_open_router_categories, + ) + + req = self._build_request( + method="GET", + path="/oauth/jwks", + base_url=base_url, + url_variables=url_variables, + request=request, + request_body_required=False, + request_has_path_params=False, + request_has_query_params=True, + user_agent_header="user-agent", + accept_header_value="application/json", + http_headers=http_headers, + _globals=operations.ListOauthJwksGlobals( + 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="listOauthJwks", + oauth2_scopes=None, + security_source=get_security_from_env( + self.sdk_configuration.security, components.Security + ), + tags=["OAuth"], + 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.OAuthJwks, 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 list_oauth_jwks_async( + self, + *, + 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.OAuthJwks: + r"""OpenRouter access token signing keys + + RFC 7517 JWK Set containing the public keys OpenRouter signs access tokens with. + + :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.ListOauthJwksRequest( + http_referer=http_referer, + x_open_router_title=x_open_router_title, + x_open_router_categories=x_open_router_categories, + ) + + req = self._build_request_async( + method="GET", + path="/oauth/jwks", + base_url=base_url, + url_variables=url_variables, + request=request, + request_body_required=False, + request_has_path_params=False, + request_has_query_params=True, + user_agent_header="user-agent", + accept_header_value="application/json", + http_headers=http_headers, + _globals=operations.ListOauthJwksGlobals( + 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="listOauthJwks", + oauth2_scopes=None, + security_source=get_security_from_env( + self.sdk_configuration.security, components.Security + ), + tags=["OAuth"], + 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.OAuthJwks, 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 create_oauth_token( + self, + *, + federation_policy_id: str, + grant_type: components.GrantType, + subject_token: str, + subject_token_type: components.SubjectTokenType, + http_referer: Optional[str] = None, + x_open_router_title: Optional[str] = None, + x_open_router_categories: Optional[str] = None, + requested_token_type: Optional[components.RequestedTokenType] = None, + scope: Optional[components.Scope] = None, + retries: OptionalNullable[utils.RetryConfig] = UNSET, + server_url: Optional[str] = None, + timeout_ms: Optional[int] = None, + http_headers: Optional[Mapping[str, str]] = None, + ) -> components.TokenExchangeResponse: + r"""Exchange a workload identity token + + RFC 8693 token exchange. Presents a JWT from an issuer your organization trusts (Settings → Workload identity) and receives a short-lived OpenRouter access token that acts as the API key the matching federation policy targets. + + :param federation_policy_id: The federation policy to evaluate, from Settings → Workload identity. Binds the exchange to one organization. + :param grant_type: Must be `urn:ietf:params:oauth:grant-type:token-exchange`. + :param subject_token: The JWT issued by your identity provider. + :param subject_token_type: Must be `urn:ietf:params:oauth:token-type:jwt`. + :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 requested_token_type: Optional; when present must be `urn:ietf:params:oauth:token-type:access_token`. + :param scope: Optional; only `inference` is available. + :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.CreateOauthTokenRequest( + http_referer=http_referer, + x_open_router_title=x_open_router_title, + x_open_router_categories=x_open_router_categories, + token_exchange_request=components.TokenExchangeRequest( + federation_policy_id=federation_policy_id, + grant_type=grant_type, + requested_token_type=requested_token_type, + scope=scope, + subject_token=subject_token, + subject_token_type=subject_token_type, + ), + ) + + req = self._build_request( + method="POST", + path="/oauth/token", + base_url=base_url, + url_variables=url_variables, + request=request, + request_body_required=True, + request_has_path_params=False, + request_has_query_params=True, + user_agent_header="user-agent", + accept_header_value="application/json", + http_headers=http_headers, + _globals=operations.CreateOauthTokenGlobals( + 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, + get_serialized_body=lambda: utils.serialize_request_body( + request.token_exchange_request, + False, + False, + "form", + components.TokenExchangeRequest, + ), + 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="createOauthToken", + oauth2_scopes=None, + security_source=get_security_from_env( + self.sdk_configuration.security, components.Security + ), + tags=["OAuth"], + 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.TokenExchangeResponse, http_res) + if utils.match_response(http_res, ["400", "429"], "application/json"): + response_data = unmarshal_json_response( + errors.OAuthErrorResponseData, http_res + ) + raise errors.OAuthErrorResponse(response_data, http_res) + if utils.match_response(http_res, ["500", "503"], "application/json"): + response_data = unmarshal_json_response( + errors.OAuthErrorResponseData, http_res + ) + raise errors.OAuthErrorResponse(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 create_oauth_token_async( + self, + *, + federation_policy_id: str, + grant_type: components.GrantType, + subject_token: str, + subject_token_type: components.SubjectTokenType, + http_referer: Optional[str] = None, + x_open_router_title: Optional[str] = None, + x_open_router_categories: Optional[str] = None, + requested_token_type: Optional[components.RequestedTokenType] = None, + scope: Optional[components.Scope] = None, + retries: OptionalNullable[utils.RetryConfig] = UNSET, + server_url: Optional[str] = None, + timeout_ms: Optional[int] = None, + http_headers: Optional[Mapping[str, str]] = None, + ) -> components.TokenExchangeResponse: + r"""Exchange a workload identity token + + RFC 8693 token exchange. Presents a JWT from an issuer your organization trusts (Settings → Workload identity) and receives a short-lived OpenRouter access token that acts as the API key the matching federation policy targets. + + :param federation_policy_id: The federation policy to evaluate, from Settings → Workload identity. Binds the exchange to one organization. + :param grant_type: Must be `urn:ietf:params:oauth:grant-type:token-exchange`. + :param subject_token: The JWT issued by your identity provider. + :param subject_token_type: Must be `urn:ietf:params:oauth:token-type:jwt`. + :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 requested_token_type: Optional; when present must be `urn:ietf:params:oauth:token-type:access_token`. + :param scope: Optional; only `inference` is available. + :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.CreateOauthTokenRequest( + http_referer=http_referer, + x_open_router_title=x_open_router_title, + x_open_router_categories=x_open_router_categories, + token_exchange_request=components.TokenExchangeRequest( + federation_policy_id=federation_policy_id, + grant_type=grant_type, + requested_token_type=requested_token_type, + scope=scope, + subject_token=subject_token, + subject_token_type=subject_token_type, + ), + ) + + req = self._build_request_async( + method="POST", + path="/oauth/token", + base_url=base_url, + url_variables=url_variables, + request=request, + request_body_required=True, + request_has_path_params=False, + request_has_query_params=True, + user_agent_header="user-agent", + accept_header_value="application/json", + http_headers=http_headers, + _globals=operations.CreateOauthTokenGlobals( + 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, + get_serialized_body=lambda: utils.serialize_request_body( + request.token_exchange_request, + False, + False, + "form", + components.TokenExchangeRequest, + ), + 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="createOauthToken", + oauth2_scopes=None, + security_source=get_security_from_env( + self.sdk_configuration.security, components.Security + ), + tags=["OAuth"], + 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.TokenExchangeResponse, http_res) + if utils.match_response(http_res, ["400", "429"], "application/json"): + response_data = unmarshal_json_response( + errors.OAuthErrorResponseData, http_res + ) + raise errors.OAuthErrorResponse(response_data, http_res) + if utils.match_response(http_res, ["500", "503"], "application/json"): + response_data = unmarshal_json_response( + errors.OAuthErrorResponseData, http_res + ) + raise errors.OAuthErrorResponse(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) diff --git a/src/openrouter/operations/__init__.py b/src/openrouter/operations/__init__.py index 15345546..b76c802a 100644 --- a/src/openrouter/operations/__init__.py +++ b/src/openrouter/operations/__init__.py @@ -149,6 +149,12 @@ CreateKeysResponse, CreateKeysResponseTypedDict, ) + from .createoauthtoken import ( + CreateOauthTokenGlobals, + CreateOauthTokenGlobalsTypedDict, + CreateOauthTokenRequest, + CreateOauthTokenRequestTypedDict, + ) from .createobservabilitydestination import ( CreateObservabilityDestinationGlobals, CreateObservabilityDestinationGlobalsTypedDict, @@ -630,6 +636,12 @@ ListModelsUserSecurity, ListModelsUserSecurityTypedDict, ) + from .listoauthjwks import ( + ListOauthJwksGlobals, + ListOauthJwksGlobalsTypedDict, + ListOauthJwksRequest, + ListOauthJwksRequestTypedDict, + ) from .listobservabilitydestinations import ( ListObservabilityDestinationsGlobals, ListObservabilityDestinationsGlobalsTypedDict, @@ -954,6 +966,10 @@ "CreateKeysRequestTypedDict", "CreateKeysResponse", "CreateKeysResponseTypedDict", + "CreateOauthTokenGlobals", + "CreateOauthTokenGlobalsTypedDict", + "CreateOauthTokenRequest", + "CreateOauthTokenRequestTypedDict", "CreateObservabilityDestinationGlobals", "CreateObservabilityDestinationGlobalsTypedDict", "CreateObservabilityDestinationRequest", @@ -1298,6 +1314,10 @@ "ListModelsUserResponseTypedDict", "ListModelsUserSecurity", "ListModelsUserSecurityTypedDict", + "ListOauthJwksGlobals", + "ListOauthJwksGlobalsTypedDict", + "ListOauthJwksRequest", + "ListOauthJwksRequestTypedDict", "ListObservabilityDestinationsGlobals", "ListObservabilityDestinationsGlobalsTypedDict", "ListObservabilityDestinationsRequest", @@ -1604,6 +1624,10 @@ "CreateKeysRequestTypedDict": ".createkeys", "CreateKeysResponse": ".createkeys", "CreateKeysResponseTypedDict": ".createkeys", + "CreateOauthTokenGlobals": ".createoauthtoken", + "CreateOauthTokenGlobalsTypedDict": ".createoauthtoken", + "CreateOauthTokenRequest": ".createoauthtoken", + "CreateOauthTokenRequestTypedDict": ".createoauthtoken", "CreateObservabilityDestinationGlobals": ".createobservabilitydestination", "CreateObservabilityDestinationGlobalsTypedDict": ".createobservabilitydestination", "CreateObservabilityDestinationRequest": ".createobservabilitydestination", @@ -1963,6 +1987,10 @@ "ListModelsUserResponseTypedDict": ".listmodelsuser", "ListModelsUserSecurity": ".listmodelsuser", "ListModelsUserSecurityTypedDict": ".listmodelsuser", + "ListOauthJwksGlobals": ".listoauthjwks", + "ListOauthJwksGlobalsTypedDict": ".listoauthjwks", + "ListOauthJwksRequest": ".listoauthjwks", + "ListOauthJwksRequestTypedDict": ".listoauthjwks", "ListObservabilityDestinationsGlobals": ".listobservabilitydestinations", "ListObservabilityDestinationsGlobalsTypedDict": ".listobservabilitydestinations", "ListObservabilityDestinationsRequest": ".listobservabilitydestinations", diff --git a/src/openrouter/operations/createoauthtoken.py b/src/openrouter/operations/createoauthtoken.py new file mode 100644 index 00000000..6c66e041 --- /dev/null +++ b/src/openrouter/operations/createoauthtoken.py @@ -0,0 +1,150 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +from __future__ import annotations +from openrouter.components import ( + tokenexchangerequest as components_tokenexchangerequest, +) +from openrouter.types import BaseModel, UNSET_SENTINEL +from openrouter.utils import FieldMetadata, HeaderMetadata, RequestMetadata +import pydantic +from pydantic import model_serializer +from typing import Optional +from typing_extensions import Annotated, NotRequired, TypedDict + + +class CreateOauthTokenGlobalsTypedDict(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 CreateOauthTokenGlobals(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 CreateOauthTokenRequestTypedDict(TypedDict): + token_exchange_request: ( + components_tokenexchangerequest.TokenExchangeRequestTypedDict + ) + 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 CreateOauthTokenRequest(BaseModel): + token_exchange_request: Annotated[ + components_tokenexchangerequest.TokenExchangeRequest, + FieldMetadata( + request=RequestMetadata(media_type="application/x-www-form-urlencoded") + ), + ] + + 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/operations/listoauthjwks.py b/src/openrouter/operations/listoauthjwks.py new file mode 100644 index 00000000..f79a46a1 --- /dev/null +++ b/src/openrouter/operations/listoauthjwks.py @@ -0,0 +1,137 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +from __future__ import annotations +from openrouter.types import BaseModel, UNSET_SENTINEL +from openrouter.utils import FieldMetadata, HeaderMetadata +import pydantic +from pydantic import model_serializer +from typing import Optional +from typing_extensions import Annotated, NotRequired, TypedDict + + +class ListOauthJwksGlobalsTypedDict(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 ListOauthJwksGlobals(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 ListOauthJwksRequestTypedDict(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 ListOauthJwksRequest(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 diff --git a/uv.lock b/uv.lock index e792c40f..0466cb73 100644 --- a/uv.lock +++ b/uv.lock @@ -213,7 +213,7 @@ wheels = [ [[package]] name = "openrouter" -version = "1.1.118" +version = "1.1.119" source = { editable = "." } dependencies = [ { name = "httpcore" }, From 0ef9f19c61f69da0f057fe95077204ae967eb952 Mon Sep 17 00:00:00 2001 From: "speakeasy-github[bot]" <128539517+speakeasy-github[bot]@users.noreply.github.com> Date: Thu, 3 Sep 2026 00:28:17 +0000 Subject: [PATCH 2/2] empty commit to trigger [run-tests] workflow