diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 2261026f..b2abf22f 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.141.0"
+ ".": "0.142.0"
}
diff --git a/.stats.yml b/.stats.yml
index ea0d5273..4725ed91 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1 +1 @@
-configured_endpoints: 176
+configured_endpoints: 178
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cc8125ed..58184c3c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
# Changelog
+## [0.142.0](https://github.com/kernel/kernel-node-sdk/compare/v0.141.0...v0.142.0) (2026-11-06)
+
+
+### Features
+
+* Let reserved orgs list, pin and move ISP proxy IPs ([4813633](https://github.com/kernel/kernel-node-sdk/commit/4813633d168204e991058d53f6f486dcd5c08e7a))
+
## [0.141.0](https://github.com/kernel/kernel-node-sdk/compare/v0.140.0...v0.141.0) (2026-11-05)
diff --git a/api.md b/api.md
index 6386621a..491929c8 100644
--- a/api.md
+++ b/api.md
@@ -447,6 +447,18 @@ Methods:
- client.proxies.delete(idOrName) -> void
- client.proxies.check(idOrName, { ...params }) -> ProxyCheckResponse
+# ProxyIPs
+
+Types:
+
+- ProxyIP
+- ProxyIPDetail
+
+Methods:
+
+- client.proxyIPs.retrieve(ipAddress) -> ProxyIPDetail
+- client.proxyIPs.list({ ...params }) -> ProxyIPsOffsetPagination
+
# Extensions
Types:
diff --git a/package.json b/package.json
index 6d234039..95ac7f97 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@onkernel/sdk",
- "version": "0.141.0",
+ "version": "0.142.0",
"description": "The official TypeScript library for the Kernel API",
"author": "Kernel <>",
"types": "dist/index.d.ts",
diff --git a/src/client.ts b/src/client.ts
index a9d1f37a..7b86b4bc 100644
--- a/src/client.ts
+++ b/src/client.ts
@@ -136,6 +136,13 @@ import {
ProxyUpdateParams,
ProxyUpdateResponse,
} from './resources/proxies';
+import {
+ ProxyIP,
+ ProxyIPDetail,
+ ProxyIPListParams,
+ ProxyIPs,
+ ProxyIPsOffsetPagination,
+} from './resources/proxy-ips';
import {
VaultProviderConfig,
VaultProviderConfigCreateParams,
@@ -1094,6 +1101,10 @@ export class Kernel {
* Create and manage proxy configurations for routing browser traffic.
*/
proxies: API.Proxies = new API.Proxies(this);
+ /**
+ * Create and manage proxy configurations for routing browser traffic.
+ */
+ proxyIPs: API.ProxyIPs = new API.ProxyIPs(this);
/**
* Create, list, retrieve, and delete browser extensions.
*/
@@ -1140,6 +1151,7 @@ Kernel.Profiles = Profiles;
Kernel.Auth = Auth;
Kernel.Telemetry = Telemetry;
Kernel.Proxies = Proxies;
+Kernel.ProxyIPs = ProxyIPs;
Kernel.Extensions = Extensions;
Kernel.BrowserPools = BrowserPools;
Kernel.VaultProviderConfigs = VaultProviderConfigs;
@@ -1294,6 +1306,14 @@ export declare namespace Kernel {
type ProxyCheckParams as ProxyCheckParams,
};
+ export {
+ ProxyIPs as ProxyIPs,
+ type ProxyIP as ProxyIP,
+ type ProxyIPDetail as ProxyIPDetail,
+ type ProxyIPsOffsetPagination as ProxyIPsOffsetPagination,
+ type ProxyIPListParams as ProxyIPListParams,
+ };
+
export {
Extensions as Extensions,
type ExtensionListResponse as ExtensionListResponse,
diff --git a/src/resources/config-registry/config-registry.ts b/src/resources/config-registry/config-registry.ts
index d98336d6..dc12551b 100644
--- a/src/resources/config-registry/config-registry.ts
+++ b/src/resources/config-registry/config-registry.ts
@@ -337,9 +337,21 @@ export namespace Proxy {
export interface IspProxyConfig {
/**
* ISO 3166 country code. Supported countries are US, GB, FR, DE, SG, and KR.
- * Defaults to US if not provided.
+ * Defaults to US if not provided, or to the country of ip_address when that is
+ * set.
*/
country?: string;
+
+ /**
+ * Reserved exit IP to pin the proxy to. Available only to organizations with a
+ * reserved ISP allocation; the IP must be active in it (see GET /proxy_ips) and,
+ * when country is also set, in that country. Omit to let Kernel choose an IP. A
+ * proxy read includes it only when the proxy's primary exit IP is one of the
+ * organization's reserved IPs; every ISP proxy's exit IP is on the top-level
+ * ip_address. An IP outside the allocation is rejected with code ip_not_reserved;
+ * one that cannot currently be assigned, with 409 ip_unavailable.
+ */
+ ip_address?: string;
}
/**
diff --git a/src/resources/index.ts b/src/resources/index.ts
index c3caae59..828bb65c 100644
--- a/src/resources/index.ts
+++ b/src/resources/index.ts
@@ -195,6 +195,13 @@ export {
type ProxyCheckParams,
type ProxyListResponsesOffsetPagination,
} from './proxies';
+export {
+ ProxyIPs,
+ type ProxyIP,
+ type ProxyIPDetail,
+ type ProxyIPListParams,
+ type ProxyIPsOffsetPagination,
+} from './proxy-ips';
export {
SearchResource,
type Attempt,
diff --git a/src/resources/proxies.ts b/src/resources/proxies.ts
index 0c7809aa..3b6c1ba4 100644
--- a/src/resources/proxies.ts
+++ b/src/resources/proxies.ts
@@ -39,14 +39,17 @@ export class Proxies extends APIResource {
}
/**
- * Update a proxy's name. Proxy names are not unique and duplicate names are
- * allowed.
+ * Update a proxy's name, or move an ISP proxy to another reserved exit IP. Proxy
+ * names are not unique and duplicate names are allowed. Moving requires a reserved
+ * ISP allocation and is accepted only for proxies of type isp: the new endpoint is
+ * probed first and nothing changes if the probe fails. An IP outside the
+ * allocation is a 400 with code ip_not_reserved. A 409 means the IP cannot
+ * currently be assigned or the proxy was changed concurrently; read it back and
+ * retry.
*
* @example
* ```ts
- * const proxy = await client.proxies.update('id_or_name', {
- * name: 'my-renamed-proxy',
- * });
+ * const proxy = await client.proxies.update('id_or_name');
* ```
*/
update(
@@ -172,9 +175,21 @@ export namespace ProxyCreateResponse {
export interface IspProxyConfig {
/**
* ISO 3166 country code. Supported countries are US, GB, FR, DE, SG, and KR.
- * Defaults to US if not provided.
+ * Defaults to US if not provided, or to the country of ip_address when that is
+ * set.
*/
country?: string;
+
+ /**
+ * Reserved exit IP to pin the proxy to. Available only to organizations with a
+ * reserved ISP allocation; the IP must be active in it (see GET /proxy_ips) and,
+ * when country is also set, in that country. Omit to let Kernel choose an IP. A
+ * proxy read includes it only when the proxy's primary exit IP is one of the
+ * organization's reserved IPs; every ISP proxy's exit IP is on the top-level
+ * ip_address. An IP outside the allocation is rejected with code ip_not_reserved;
+ * one that cannot currently be assigned, with 409 ip_unavailable.
+ */
+ ip_address?: string;
}
/**
@@ -321,9 +336,21 @@ export namespace ProxyRetrieveResponse {
export interface IspProxyConfig {
/**
* ISO 3166 country code. Supported countries are US, GB, FR, DE, SG, and KR.
- * Defaults to US if not provided.
+ * Defaults to US if not provided, or to the country of ip_address when that is
+ * set.
*/
country?: string;
+
+ /**
+ * Reserved exit IP to pin the proxy to. Available only to organizations with a
+ * reserved ISP allocation; the IP must be active in it (see GET /proxy_ips) and,
+ * when country is also set, in that country. Omit to let Kernel choose an IP. A
+ * proxy read includes it only when the proxy's primary exit IP is one of the
+ * organization's reserved IPs; every ISP proxy's exit IP is on the top-level
+ * ip_address. An IP outside the allocation is rejected with code ip_not_reserved;
+ * one that cannot currently be assigned, with 409 ip_unavailable.
+ */
+ ip_address?: string;
}
/**
@@ -470,9 +497,21 @@ export namespace ProxyUpdateResponse {
export interface IspProxyConfig {
/**
* ISO 3166 country code. Supported countries are US, GB, FR, DE, SG, and KR.
- * Defaults to US if not provided.
+ * Defaults to US if not provided, or to the country of ip_address when that is
+ * set.
*/
country?: string;
+
+ /**
+ * Reserved exit IP to pin the proxy to. Available only to organizations with a
+ * reserved ISP allocation; the IP must be active in it (see GET /proxy_ips) and,
+ * when country is also set, in that country. Omit to let Kernel choose an IP. A
+ * proxy read includes it only when the proxy's primary exit IP is one of the
+ * organization's reserved IPs; every ISP proxy's exit IP is on the top-level
+ * ip_address. An IP outside the allocation is rejected with code ip_not_reserved;
+ * one that cannot currently be assigned, with 409 ip_unavailable.
+ */
+ ip_address?: string;
}
/**
@@ -619,9 +658,21 @@ export namespace ProxyListResponse {
export interface IspProxyConfig {
/**
* ISO 3166 country code. Supported countries are US, GB, FR, DE, SG, and KR.
- * Defaults to US if not provided.
+ * Defaults to US if not provided, or to the country of ip_address when that is
+ * set.
*/
country?: string;
+
+ /**
+ * Reserved exit IP to pin the proxy to. Available only to organizations with a
+ * reserved ISP allocation; the IP must be active in it (see GET /proxy_ips) and,
+ * when country is also set, in that country. Omit to let Kernel choose an IP. A
+ * proxy read includes it only when the proxy's primary exit IP is one of the
+ * organization's reserved IPs; every ISP proxy's exit IP is on the top-level
+ * ip_address. An IP outside the allocation is rejected with code ip_not_reserved;
+ * one that cannot currently be assigned, with 409 ip_unavailable.
+ */
+ ip_address?: string;
}
/**
@@ -768,9 +819,21 @@ export namespace ProxyCheckResponse {
export interface IspProxyConfig {
/**
* ISO 3166 country code. Supported countries are US, GB, FR, DE, SG, and KR.
- * Defaults to US if not provided.
+ * Defaults to US if not provided, or to the country of ip_address when that is
+ * set.
*/
country?: string;
+
+ /**
+ * Reserved exit IP to pin the proxy to. Available only to organizations with a
+ * reserved ISP allocation; the IP must be active in it (see GET /proxy_ips) and,
+ * when country is also set, in that country. Omit to let Kernel choose an IP. A
+ * proxy read includes it only when the proxy's primary exit IP is one of the
+ * organization's reserved IPs; every ISP proxy's exit IP is on the top-level
+ * ip_address. An IP outside the allocation is rejected with code ip_not_reserved;
+ * one that cannot currently be assigned, with 409 ip_unavailable.
+ */
+ ip_address?: string;
}
/**
@@ -897,9 +960,21 @@ export namespace ProxyCreateParams {
export interface IspProxyConfig {
/**
* ISO 3166 country code. Supported countries are US, GB, FR, DE, SG, and KR.
- * Defaults to US if not provided.
+ * Defaults to US if not provided, or to the country of ip_address when that is
+ * set.
*/
country?: string;
+
+ /**
+ * Reserved exit IP to pin the proxy to. Available only to organizations with a
+ * reserved ISP allocation; the IP must be active in it (see GET /proxy_ips) and,
+ * when country is also set, in that country. Omit to let Kernel choose an IP. A
+ * proxy read includes it only when the proxy's primary exit IP is one of the
+ * organization's reserved IPs; every ISP proxy's exit IP is on the top-level
+ * ip_address. An IP outside the allocation is rejected with code ip_not_reserved;
+ * one that cannot currently be assigned, with 409 ip_unavailable.
+ */
+ ip_address?: string;
}
/**
@@ -994,14 +1069,42 @@ export namespace ProxyCreateParams {
}
export interface ProxyUpdateParams {
+ /**
+ * Changes to an ISP proxy's exit IP. Accepted only for proxies of type `isp`.
+ */
+ config?: ProxyUpdateParams.Config;
+
/**
* New proxy name. Proxy names are trimmed and length-checked only; duplicates are
* allowed because proxies are updated by ID, not by name.
*/
- name: string;
+ name?: string;
+}
+
+export namespace ProxyUpdateParams {
+ /**
+ * Changes to an ISP proxy's exit IP. Accepted only for proxies of type `isp`.
+ */
+ export interface Config {
+ /**
+ * Reserved exit IP to move the proxy to. The IP must be active in the
+ * organization's allocation and in the proxy's country. The proxy keeps its ID.
+ * The new endpoint is probed before anything changes; a failed probe leaves the
+ * proxy as it was. Live browsers open new connections on the new IP within a few
+ * seconds; established connections drain on the old one.
+ */
+ ip_address: string;
+ }
}
export interface ProxyListParams extends OffsetPaginationParams {
+ /**
+ * Exact match on the primary exit IP of ISP proxies. Must be an IPv4 address. Only
+ * ISP proxies are matched: the ip_address shown on other proxy types is a one-time
+ * observation, not a stable identity.
+ */
+ ip_address?: string;
+
/**
* Exact-match filter on proxy name using the database collation. In production,
* matching is case- and accent-insensitive. Names are not required to be unique,
diff --git a/src/resources/proxy-ips.ts b/src/resources/proxy-ips.ts
new file mode 100644
index 00000000..18436b0c
--- /dev/null
+++ b/src/resources/proxy-ips.ts
@@ -0,0 +1,130 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import { APIResource } from '../core/resource';
+import { APIPromise } from '../core/api-promise';
+import { OffsetPagination, type OffsetPaginationParams, PagePromise } from '../core/pagination';
+import { RequestOptions } from '../internal/request-options';
+import { path } from '../internal/utils/path';
+
+/**
+ * Create and manage proxy configurations for routing browser traffic.
+ */
+export class ProxyIPs extends APIResource {
+ /**
+ * Retrieve one reserved IP with the ISP proxies using it as their primary exit.
+ * proxy_count spans the organization; proxies lists only those in the current
+ * project. Returns 404 when the IP is not in the organization's allocation and 403
+ * with code reserved_isp_not_enabled when the organization has none. Scoped API
+ * keys require proxies:read on the whole project or organization, not on
+ * individual proxies; otherwise the operation returns 403 with code
+ * insufficient_scope.
+ */
+ retrieve(ipAddress: string, options?: RequestOptions): APIPromise {
+ return this._client.get(path`/proxy_ips/${ipAddress}`, options);
+ }
+
+ /**
+ * List the IP addresses reserved for the organization's ISP proxies, with each
+ * IP's country and whether it can currently be assigned. Available only to
+ * organizations with a reserved ISP allocation; others receive a 403 with code
+ * reserved_isp_not_enabled. Served from the allocation itself, so IPs appear
+ * whether or not a proxy uses them. Scoped API keys require proxies:read on the
+ * whole project or organization, not on individual proxies; otherwise the
+ * operation returns 403 with code insufficient_scope.
+ */
+ list(
+ query: ProxyIPListParams | null | undefined = {},
+ options?: RequestOptions,
+ ): PagePromise {
+ return this._client.getAPIList('/proxy_ips', OffsetPagination, { query, ...options });
+ }
+}
+
+export type ProxyIPsOffsetPagination = OffsetPagination;
+
+/**
+ * One IP address reserved for the organization's ISP proxies.
+ */
+export interface ProxyIP {
+ /**
+ * ISO 3166 country code of the IP.
+ */
+ country: string;
+
+ /**
+ * Reserved exit IP address.
+ */
+ ip_address: string;
+
+ /**
+ * Whether the IP can currently be assigned. An excluded IP is listed but cannot be
+ * pinned or moved to; proxies already on it keep working.
+ */
+ status: 'active' | 'excluded';
+}
+
+/**
+ * A reserved IP with the ISP proxies using it as their primary exit. Reservations
+ * are organization-wide, so proxy_count covers every project while proxies lists
+ * only those in the current project.
+ */
+export interface ProxyIPDetail {
+ /**
+ * ISO 3166 country code of the IP.
+ */
+ country: string;
+
+ /**
+ * Reserved exit IP address.
+ */
+ ip_address: string;
+
+ /**
+ * ISP proxies in the current project whose primary exit IP is this address.
+ */
+ proxies: Array;
+
+ /**
+ * Number of ISP proxies across the organization whose primary exit IP is this
+ * address.
+ */
+ proxy_count: number;
+
+ /**
+ * Whether the IP can currently be assigned. An excluded IP is listed but cannot be
+ * pinned or moved to; proxies already on it keep working.
+ */
+ status: 'active' | 'excluded';
+}
+
+export namespace ProxyIPDetail {
+ /**
+ * An ISP proxy whose primary exit is the reserved IP.
+ */
+ export interface Proxy {
+ id: string;
+
+ name?: string;
+ }
+}
+
+export interface ProxyIPListParams extends OffsetPaginationParams {
+ /**
+ * ISO 3166 country code to filter by. Must be a country ISP proxies support.
+ */
+ country?: string;
+
+ /**
+ * Filter by whether the IP can currently be assigned.
+ */
+ status?: 'active' | 'excluded';
+}
+
+export declare namespace ProxyIPs {
+ export {
+ type ProxyIP as ProxyIP,
+ type ProxyIPDetail as ProxyIPDetail,
+ type ProxyIPsOffsetPagination as ProxyIPsOffsetPagination,
+ type ProxyIPListParams as ProxyIPListParams,
+ };
+}
diff --git a/src/resources/shared.ts b/src/resources/shared.ts
index ac7e1b93..1dac2029 100644
--- a/src/resources/shared.ts
+++ b/src/resources/shared.ts
@@ -79,12 +79,14 @@ export interface BrowserProfile {
*/
export interface BrowserViewport {
/**
- * Browser window height in pixels. Any positive integer is accepted.
+ * Browser window height in pixels. Any positive integer is accepted; headful
+ * browsers require at least 64.
*/
height: number;
/**
- * Browser window width in pixels. Any positive integer is accepted.
+ * Browser window width in pixels. Any positive integer is accepted; headful
+ * browsers require at least 64.
*/
width: number;
diff --git a/src/version.ts b/src/version.ts
index 98896b65..b62c0902 100644
--- a/src/version.ts
+++ b/src/version.ts
@@ -1 +1 @@
-export const VERSION = '0.141.0'; // x-release-please-version
+export const VERSION = '0.142.0'; // x-release-please-version
diff --git a/tests/api-resources/proxies.test.ts b/tests/api-resources/proxies.test.ts
index 8fb2ba08..6393109f 100644
--- a/tests/api-resources/proxies.test.ts
+++ b/tests/api-resources/proxies.test.ts
@@ -25,7 +25,7 @@ describe('resource proxies', () => {
const response = await client.proxies.create({
type: 'isp',
bypass_hosts: ['string'],
- config: { country: 'US' },
+ config: { country: 'US', ip_address: '203.0.113.10' },
name: 'name',
protocol: 'http',
});
@@ -44,8 +44,8 @@ describe('resource proxies', () => {
});
// Mock server tests are disabled
- test.skip('update: only required params', async () => {
- const responsePromise = client.proxies.update('id_or_name', { name: 'my-renamed-proxy' });
+ test.skip('update', async () => {
+ const responsePromise = client.proxies.update('id_or_name', {});
const rawResponse = await responsePromise.asResponse();
expect(rawResponse).toBeInstanceOf(Response);
const response = await responsePromise;
@@ -55,11 +55,6 @@ describe('resource proxies', () => {
expect(dataAndResponse.response).toBe(rawResponse);
});
- // Mock server tests are disabled
- test.skip('update: required and optional params', async () => {
- const response = await client.proxies.update('id_or_name', { name: 'my-renamed-proxy' });
- });
-
// Mock server tests are disabled
test.skip('list', async () => {
const responsePromise = client.proxies.list();
@@ -78,6 +73,7 @@ describe('resource proxies', () => {
await expect(
client.proxies.list(
{
+ ip_address: 'ip_address',
limit: 1,
name: 'name',
offset: 0,
diff --git a/tests/api-resources/proxy-ips.test.ts b/tests/api-resources/proxy-ips.test.ts
new file mode 100644
index 00000000..bf92b306
--- /dev/null
+++ b/tests/api-resources/proxy-ips.test.ts
@@ -0,0 +1,50 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import Kernel from '@onkernel/sdk';
+
+const client = new Kernel({
+ apiKey: 'My API Key',
+ baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010',
+});
+
+describe('resource proxyIPs', () => {
+ // Mock server tests are disabled
+ test.skip('retrieve', async () => {
+ const responsePromise = client.proxyIPs.retrieve('ip_address');
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('list', async () => {
+ const responsePromise = client.proxyIPs.list();
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('list: request options and params are passed correctly', async () => {
+ // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
+ await expect(
+ client.proxyIPs.list(
+ {
+ country: 'country',
+ limit: 1,
+ offset: 0,
+ status: 'active',
+ },
+ { path: '/_stainless_unknown_path' },
+ ),
+ ).rejects.toThrow(Kernel.NotFoundError);
+ });
+});