diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index ab58c19..9ad4bf8 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.141.0"
+ ".": "0.142.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index ea0d527..4725ed9 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1 +1 @@
-configured_endpoints: 176
+configured_endpoints: 178
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e3030bc..732e255 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
# Changelog
+## [0.142.0](https://github.com/kernel/kernel-go-sdk/compare/v0.141.0...v0.142.0) (2026-11-06)
+
+
+### Features
+
+* Let reserved orgs list, pin and move ISP proxy IPs ([cc6cd8e](https://github.com/kernel/kernel-go-sdk/commit/cc6cd8ecff93dbb826e7fb7887f3cd3642631366))
+
## [0.141.0](https://github.com/kernel/kernel-go-sdk/compare/v0.139.0...v0.141.0) (2026-11-05)
diff --git a/README.md b/README.md
index 3dd397d..a7620b4 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ Or to pin the version:
```sh
-go get -u 'github.com/kernel/kernel-go-sdk@v0.141.0'
+go get -u 'github.com/kernel/kernel-go-sdk@v0.142.0'
```
diff --git a/api.md b/api.md
index 6d37f54..a12723e 100644
--- a/api.md
+++ b/api.md
@@ -479,6 +479,18 @@ Methods:
- client.Proxies.Delete(ctx context.Context, idOrName string) error
- client.Proxies.Check(ctx context.Context, idOrName string, body kernel.ProxyCheckParams) (\*kernel.ProxyCheckResponse, error)
+# ProxyIPs
+
+Response Types:
+
+- kernel.ProxyIP
+- kernel.ProxyIPDetail
+
+Methods:
+
+- client.ProxyIPs.Get(ctx context.Context, ipAddress string) (\*kernel.ProxyIPDetail, error)
+- client.ProxyIPs.List(ctx context.Context, query kernel.ProxyIPListParams) (\*pagination.OffsetPagination[kernel.ProxyIP], error)
+
# Extensions
Response Types:
diff --git a/client.go b/client.go
index 13c6264..b3a0f98 100644
--- a/client.go
+++ b/client.go
@@ -36,6 +36,8 @@ type Client struct {
Telemetry TelemetryService
// Create and manage proxy configurations for routing browser traffic.
Proxies ProxyService
+ // Create and manage proxy configurations for routing browser traffic.
+ ProxyIPs ProxyIPService
// Create, list, retrieve, and delete browser extensions.
Extensions ExtensionService
// Create and manage browser pools for acquiring and releasing browsers.
@@ -101,6 +103,7 @@ func NewClient(opts ...option.RequestOption) (r Client) {
r.Auth = NewAuthService(opts...)
r.Telemetry = NewTelemetryService(opts...)
r.Proxies = NewProxyService(opts...)
+ r.ProxyIPs = NewProxyIPService(opts...)
r.Extensions = NewExtensionService(opts...)
r.BrowserPools = NewBrowserPoolService(opts...)
r.VaultProviderConfigs = NewVaultProviderConfigService(opts...)
diff --git a/configregistry.go b/configregistry.go
index 589c791..a822e8d 100644
--- a/configregistry.go
+++ b/configregistry.go
@@ -507,6 +507,8 @@ func (r *ProxyManagedCreate) UnmarshalJSON(data []byte) error {
// Use the methods beginning with 'As' to cast the union to one of its variants.
type ProxyManagedCreateConfigUnion struct {
Country string `json:"country"`
+ // This field is from variant [ProxyManagedCreateConfigIsp].
+ IPAddress string `json:"ip_address"`
// This field is from variant [ProxyManagedCreateConfigResidential].
Asn string `json:"asn"`
City string `json:"city"`
@@ -526,18 +528,19 @@ type ProxyManagedCreateConfigUnion struct {
// This field is from variant [ProxyManagedCreateConfigCustom].
Username string `json:"username"`
JSON struct {
- Country respjson.Field
- Asn respjson.Field
- City respjson.Field
- Os respjson.Field
- State respjson.Field
- Zip respjson.Field
- Host respjson.Field
- Port respjson.Field
- CaBundle respjson.Field
- Password respjson.Field
- Username respjson.Field
- raw string
+ Country respjson.Field
+ IPAddress respjson.Field
+ Asn respjson.Field
+ City respjson.Field
+ Os respjson.Field
+ State respjson.Field
+ Zip respjson.Field
+ Host respjson.Field
+ Port respjson.Field
+ CaBundle respjson.Field
+ Password respjson.Field
+ Username respjson.Field
+ raw string
} `json:"-"`
}
@@ -571,11 +574,21 @@ func (r *ProxyManagedCreateConfigUnion) UnmarshalJSON(data []byte) error {
// Configuration for an ISP proxy.
type ProxyManagedCreateConfigIsp struct {
// 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 `json:"country"`
+ // 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.
+ IPAddress string `json:"ip_address"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
Country respjson.Field
+ IPAddress respjson.Field
ExtraFields map[string]respjson.Field
raw string
} `json:"-"`
diff --git a/internal/version.go b/internal/version.go
index 16231fb..85f1142 100644
--- a/internal/version.go
+++ b/internal/version.go
@@ -2,4 +2,4 @@
package internal
-const PackageVersion = "0.141.0" // x-release-please-version
+const PackageVersion = "0.142.0" // x-release-please-version
diff --git a/proxy.go b/proxy.go
index e4ef8e6..cfa5892 100644
--- a/proxy.go
+++ b/proxy.go
@@ -65,8 +65,13 @@ func (r *ProxyService) Get(ctx context.Context, idOrName string, opts ...option.
return res, err
}
-// 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.
func (r *ProxyService) Update(ctx context.Context, idOrName string, body ProxyUpdateParams, opts ...option.RequestOption) (res *ProxyUpdateResponse, err error) {
opts = slices.Concat(r.Options, opts)
if idOrName == "" {
@@ -195,6 +200,8 @@ const (
// Use the methods beginning with 'As' to cast the union to one of its variants.
type ProxyNewResponseConfigUnion struct {
Country string `json:"country"`
+ // This field is from variant [ProxyNewResponseConfigIsp].
+ IPAddress string `json:"ip_address"`
// This field is from variant [ProxyNewResponseConfigResidential].
Asn string `json:"asn"`
City string `json:"city"`
@@ -215,6 +222,7 @@ type ProxyNewResponseConfigUnion struct {
Username string `json:"username"`
JSON struct {
Country respjson.Field
+ IPAddress respjson.Field
Asn respjson.Field
City respjson.Field
Os respjson.Field
@@ -259,11 +267,21 @@ func (r *ProxyNewResponseConfigUnion) UnmarshalJSON(data []byte) error {
// Configuration for an ISP proxy.
type ProxyNewResponseConfigIsp struct {
// 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 `json:"country"`
+ // 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.
+ IPAddress string `json:"ip_address"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
Country respjson.Field
+ IPAddress respjson.Field
ExtraFields map[string]respjson.Field
raw string
} `json:"-"`
@@ -446,6 +464,8 @@ const (
// Use the methods beginning with 'As' to cast the union to one of its variants.
type ProxyGetResponseConfigUnion struct {
Country string `json:"country"`
+ // This field is from variant [ProxyGetResponseConfigIsp].
+ IPAddress string `json:"ip_address"`
// This field is from variant [ProxyGetResponseConfigResidential].
Asn string `json:"asn"`
City string `json:"city"`
@@ -466,6 +486,7 @@ type ProxyGetResponseConfigUnion struct {
Username string `json:"username"`
JSON struct {
Country respjson.Field
+ IPAddress respjson.Field
Asn respjson.Field
City respjson.Field
Os respjson.Field
@@ -510,11 +531,21 @@ func (r *ProxyGetResponseConfigUnion) UnmarshalJSON(data []byte) error {
// Configuration for an ISP proxy.
type ProxyGetResponseConfigIsp struct {
// 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 `json:"country"`
+ // 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.
+ IPAddress string `json:"ip_address"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
Country respjson.Field
+ IPAddress respjson.Field
ExtraFields map[string]respjson.Field
raw string
} `json:"-"`
@@ -697,6 +728,8 @@ const (
// Use the methods beginning with 'As' to cast the union to one of its variants.
type ProxyUpdateResponseConfigUnion struct {
Country string `json:"country"`
+ // This field is from variant [ProxyUpdateResponseConfigIsp].
+ IPAddress string `json:"ip_address"`
// This field is from variant [ProxyUpdateResponseConfigResidential].
Asn string `json:"asn"`
City string `json:"city"`
@@ -717,6 +750,7 @@ type ProxyUpdateResponseConfigUnion struct {
Username string `json:"username"`
JSON struct {
Country respjson.Field
+ IPAddress respjson.Field
Asn respjson.Field
City respjson.Field
Os respjson.Field
@@ -761,11 +795,21 @@ func (r *ProxyUpdateResponseConfigUnion) UnmarshalJSON(data []byte) error {
// Configuration for an ISP proxy.
type ProxyUpdateResponseConfigIsp struct {
// 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 `json:"country"`
+ // 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.
+ IPAddress string `json:"ip_address"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
Country respjson.Field
+ IPAddress respjson.Field
ExtraFields map[string]respjson.Field
raw string
} `json:"-"`
@@ -948,6 +992,8 @@ const (
// Use the methods beginning with 'As' to cast the union to one of its variants.
type ProxyListResponseConfigUnion struct {
Country string `json:"country"`
+ // This field is from variant [ProxyListResponseConfigIsp].
+ IPAddress string `json:"ip_address"`
// This field is from variant [ProxyListResponseConfigResidential].
Asn string `json:"asn"`
City string `json:"city"`
@@ -968,6 +1014,7 @@ type ProxyListResponseConfigUnion struct {
Username string `json:"username"`
JSON struct {
Country respjson.Field
+ IPAddress respjson.Field
Asn respjson.Field
City respjson.Field
Os respjson.Field
@@ -1012,11 +1059,21 @@ func (r *ProxyListResponseConfigUnion) UnmarshalJSON(data []byte) error {
// Configuration for an ISP proxy.
type ProxyListResponseConfigIsp struct {
// 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 `json:"country"`
+ // 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.
+ IPAddress string `json:"ip_address"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
Country respjson.Field
+ IPAddress respjson.Field
ExtraFields map[string]respjson.Field
raw string
} `json:"-"`
@@ -1199,6 +1256,8 @@ const (
// Use the methods beginning with 'As' to cast the union to one of its variants.
type ProxyCheckResponseConfigUnion struct {
Country string `json:"country"`
+ // This field is from variant [ProxyCheckResponseConfigIsp].
+ IPAddress string `json:"ip_address"`
// This field is from variant [ProxyCheckResponseConfigResidential].
Asn string `json:"asn"`
City string `json:"city"`
@@ -1219,6 +1278,7 @@ type ProxyCheckResponseConfigUnion struct {
Username string `json:"username"`
JSON struct {
Country respjson.Field
+ IPAddress respjson.Field
Asn respjson.Field
City respjson.Field
Os respjson.Field
@@ -1263,11 +1323,21 @@ func (r *ProxyCheckResponseConfigUnion) UnmarshalJSON(data []byte) error {
// Configuration for an ISP proxy.
type ProxyCheckResponseConfigIsp struct {
// 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 `json:"country"`
+ // 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.
+ IPAddress string `json:"ip_address"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
Country respjson.Field
+ IPAddress respjson.Field
ExtraFields map[string]respjson.Field
raw string
} `json:"-"`
@@ -1453,6 +1523,14 @@ func (u *ProxyNewParamsConfigUnion) asAny() any {
return nil
}
+// Returns a pointer to the underlying variant's property, if present.
+func (u ProxyNewParamsConfigUnion) GetIPAddress() *string {
+ if vt := u.OfIsp; vt != nil && vt.IPAddress.Valid() {
+ return &vt.IPAddress.Value
+ }
+ return nil
+}
+
// Returns a pointer to the underlying variant's property, if present.
func (u ProxyNewParamsConfigUnion) GetAsn() *string {
if vt := u.OfResidential; vt != nil && vt.Asn.Valid() {
@@ -1552,8 +1630,17 @@ func (u ProxyNewParamsConfigUnion) GetState() *string {
// Configuration for an ISP proxy.
type ProxyNewParamsConfigIsp struct {
// 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 param.Opt[string] `json:"country,omitzero"`
+ // 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.
+ IPAddress param.Opt[string] `json:"ip_address,omitzero"`
paramObj
}
@@ -1660,7 +1747,9 @@ const (
type ProxyUpdateParams struct {
// 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 `json:"name" api:"required"`
+ Name param.Opt[string] `json:"name,omitzero"`
+ // Changes to an ISP proxy's exit IP. Accepted only for proxies of type `isp`.
+ Config ProxyUpdateParamsConfig `json:"config,omitzero"`
paramObj
}
@@ -1672,7 +1761,32 @@ func (r *ProxyUpdateParams) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
+// Changes to an ISP proxy's exit IP. Accepted only for proxies of type `isp`.
+//
+// The property IPAddress is required.
+type ProxyUpdateParamsConfig struct {
+ // 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.
+ IPAddress string `json:"ip_address" api:"required"`
+ paramObj
+}
+
+func (r ProxyUpdateParamsConfig) MarshalJSON() (data []byte, err error) {
+ type shadow ProxyUpdateParamsConfig
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *ProxyUpdateParamsConfig) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
type ProxyListParams struct {
+ // 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.
+ IPAddress param.Opt[string] `query:"ip_address,omitzero" json:"-"`
// Limit the number of proxies to return.
Limit param.Opt[int64] `query:"limit,omitzero" json:"-"`
// Exact-match filter on proxy name using the database collation. In production,
diff --git a/proxy_test.go b/proxy_test.go
index 50156d0..e10f4ff 100644
--- a/proxy_test.go
+++ b/proxy_test.go
@@ -31,7 +31,8 @@ func TestProxyNewWithOptionalParams(t *testing.T) {
BypassHosts: []string{"string"},
Config: kernel.ProxyNewParamsConfigUnion{
OfIsp: &kernel.ProxyNewParamsConfigIsp{
- Country: kernel.String("US"),
+ Country: kernel.String("US"),
+ IPAddress: kernel.String("203.0.113.10"),
},
},
Name: kernel.String("name"),
@@ -69,7 +70,7 @@ func TestProxyGet(t *testing.T) {
}
}
-func TestProxyUpdate(t *testing.T) {
+func TestProxyUpdateWithOptionalParams(t *testing.T) {
t.Skip("Mock server tests are disabled")
baseURL := "http://localhost:4010"
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
@@ -86,7 +87,10 @@ func TestProxyUpdate(t *testing.T) {
context.TODO(),
"id_or_name",
kernel.ProxyUpdateParams{
- Name: "my-renamed-proxy",
+ Config: kernel.ProxyUpdateParamsConfig{
+ IPAddress: "203.0.113.10",
+ },
+ Name: kernel.String("my-renamed-proxy"),
},
)
if err != nil {
@@ -112,10 +116,11 @@ func TestProxyListWithOptionalParams(t *testing.T) {
option.WithAPIKey("My API Key"),
)
_, err := client.Proxies.List(context.TODO(), kernel.ProxyListParams{
- Limit: kernel.Int(1),
- Name: kernel.String("name"),
- Offset: kernel.Int(0),
- Query: kernel.String("query"),
+ IPAddress: kernel.String("ip_address"),
+ Limit: kernel.Int(1),
+ Name: kernel.String("name"),
+ Offset: kernel.Int(0),
+ Query: kernel.String("query"),
})
if err != nil {
var apierr *kernel.Error
diff --git a/proxyip.go b/proxyip.go
new file mode 100644
index 0000000..fb81b75
--- /dev/null
+++ b/proxyip.go
@@ -0,0 +1,224 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+package kernel
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net/http"
+ "net/url"
+ "slices"
+
+ "github.com/kernel/kernel-go-sdk/internal/apijson"
+ "github.com/kernel/kernel-go-sdk/internal/apiquery"
+ "github.com/kernel/kernel-go-sdk/internal/requestconfig"
+ "github.com/kernel/kernel-go-sdk/option"
+ "github.com/kernel/kernel-go-sdk/packages/pagination"
+ "github.com/kernel/kernel-go-sdk/packages/param"
+ "github.com/kernel/kernel-go-sdk/packages/respjson"
+)
+
+// Create and manage proxy configurations for routing browser traffic.
+//
+// ProxyIPService contains methods and other services that help with interacting
+// with the kernel API.
+//
+// Note, unlike clients, this service does not read variables from the environment
+// automatically. You should not instantiate this service directly, and instead use
+// the [NewProxyIPService] method instead.
+type ProxyIPService struct {
+ Options []option.RequestOption
+}
+
+// NewProxyIPService generates a new service that applies the given options to each
+// request. These options are applied after the parent client's options (if there
+// is one), and before any request-specific options.
+func NewProxyIPService(opts ...option.RequestOption) (r ProxyIPService) {
+ r = ProxyIPService{}
+ r.Options = opts
+ return
+}
+
+// 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.
+func (r *ProxyIPService) Get(ctx context.Context, ipAddress string, opts ...option.RequestOption) (res *ProxyIPDetail, err error) {
+ opts = slices.Concat(r.Options, opts)
+ if ipAddress == "" {
+ err = errors.New("missing required ip_address parameter")
+ return nil, err
+ }
+ path := fmt.Sprintf("proxy_ips/%s", ipAddress)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
+ return res, err
+}
+
+// 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.
+func (r *ProxyIPService) List(ctx context.Context, query ProxyIPListParams, opts ...option.RequestOption) (res *pagination.OffsetPagination[ProxyIP], err error) {
+ var raw *http.Response
+ opts = slices.Concat(r.Options, opts)
+ opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...)
+ path := "proxy_ips"
+ cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, query, &res, opts...)
+ if err != nil {
+ return nil, err
+ }
+ err = cfg.Execute()
+ if err != nil {
+ return nil, err
+ }
+ res.SetPageConfig(cfg, raw)
+ return res, nil
+}
+
+// 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.
+func (r *ProxyIPService) ListAutoPaging(ctx context.Context, query ProxyIPListParams, opts ...option.RequestOption) *pagination.OffsetPaginationAutoPager[ProxyIP] {
+ return pagination.NewOffsetPaginationAutoPager(r.List(ctx, query, opts...))
+}
+
+// One IP address reserved for the organization's ISP proxies.
+type ProxyIP struct {
+ // ISO 3166 country code of the IP.
+ Country string `json:"country" api:"required"`
+ // Reserved exit IP address.
+ IPAddress string `json:"ip_address" api:"required"`
+ // 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.
+ //
+ // Any of "active", "excluded".
+ Status ProxyIPStatus `json:"status" api:"required"`
+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
+ JSON struct {
+ Country respjson.Field
+ IPAddress respjson.Field
+ Status respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+// Returns the unmodified JSON received from the API
+func (r ProxyIP) RawJSON() string { return r.JSON.raw }
+func (r *ProxyIP) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+// 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.
+type ProxyIPStatus string
+
+const (
+ ProxyIPStatusActive ProxyIPStatus = "active"
+ ProxyIPStatusExcluded ProxyIPStatus = "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.
+type ProxyIPDetail struct {
+ // ISO 3166 country code of the IP.
+ Country string `json:"country" api:"required"`
+ // Reserved exit IP address.
+ IPAddress string `json:"ip_address" api:"required"`
+ // ISP proxies in the current project whose primary exit IP is this address.
+ Proxies []ProxyIPDetailProxy `json:"proxies" api:"required"`
+ // Number of ISP proxies across the organization whose primary exit IP is this
+ // address.
+ ProxyCount int64 `json:"proxy_count" api:"required"`
+ // 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.
+ //
+ // Any of "active", "excluded".
+ Status ProxyIPDetailStatus `json:"status" api:"required"`
+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
+ JSON struct {
+ Country respjson.Field
+ IPAddress respjson.Field
+ Proxies respjson.Field
+ ProxyCount respjson.Field
+ Status respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+// Returns the unmodified JSON received from the API
+func (r ProxyIPDetail) RawJSON() string { return r.JSON.raw }
+func (r *ProxyIPDetail) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+// An ISP proxy whose primary exit is the reserved IP.
+type ProxyIPDetailProxy struct {
+ ID string `json:"id" api:"required"`
+ Name string `json:"name"`
+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
+ JSON struct {
+ ID respjson.Field
+ Name respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+// Returns the unmodified JSON received from the API
+func (r ProxyIPDetailProxy) RawJSON() string { return r.JSON.raw }
+func (r *ProxyIPDetailProxy) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+// 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.
+type ProxyIPDetailStatus string
+
+const (
+ ProxyIPDetailStatusActive ProxyIPDetailStatus = "active"
+ ProxyIPDetailStatusExcluded ProxyIPDetailStatus = "excluded"
+)
+
+type ProxyIPListParams struct {
+ // ISO 3166 country code to filter by. Must be a country ISP proxies support.
+ Country param.Opt[string] `query:"country,omitzero" json:"-"`
+ // Limit the number of IPs to return.
+ Limit param.Opt[int64] `query:"limit,omitzero" json:"-"`
+ // Offset the number of IPs to return.
+ Offset param.Opt[int64] `query:"offset,omitzero" json:"-"`
+ // Filter by whether the IP can currently be assigned.
+ //
+ // Any of "active", "excluded".
+ Status ProxyIPListParamsStatus `query:"status,omitzero" json:"-"`
+ paramObj
+}
+
+// URLQuery serializes [ProxyIPListParams]'s query parameters as `url.Values`.
+func (r ProxyIPListParams) URLQuery() (v url.Values, err error) {
+ return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
+ ArrayFormat: apiquery.ArrayQueryFormatComma,
+ NestedFormat: apiquery.NestedQueryFormatBrackets,
+ })
+}
+
+// Filter by whether the IP can currently be assigned.
+type ProxyIPListParamsStatus string
+
+const (
+ ProxyIPListParamsStatusActive ProxyIPListParamsStatus = "active"
+ ProxyIPListParamsStatusExcluded ProxyIPListParamsStatus = "excluded"
+)
diff --git a/proxyip_test.go b/proxyip_test.go
new file mode 100644
index 0000000..392622b
--- /dev/null
+++ b/proxyip_test.go
@@ -0,0 +1,65 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+package kernel_test
+
+import (
+ "context"
+ "errors"
+ "os"
+ "testing"
+
+ "github.com/kernel/kernel-go-sdk"
+ "github.com/kernel/kernel-go-sdk/internal/testutil"
+ "github.com/kernel/kernel-go-sdk/option"
+)
+
+func TestProxyIPGet(t *testing.T) {
+ t.Skip("Mock server tests are disabled")
+ baseURL := "http://localhost:4010"
+ if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
+ baseURL = envURL
+ }
+ if !testutil.CheckTestServer(t, baseURL) {
+ return
+ }
+ client := kernel.NewClient(
+ option.WithBaseURL(baseURL),
+ option.WithAPIKey("My API Key"),
+ )
+ _, err := client.ProxyIPs.Get(context.TODO(), "ip_address")
+ if err != nil {
+ var apierr *kernel.Error
+ if errors.As(err, &apierr) {
+ t.Log(string(apierr.DumpRequest(true)))
+ }
+ t.Fatalf("err should be nil: %s", err.Error())
+ }
+}
+
+func TestProxyIPListWithOptionalParams(t *testing.T) {
+ t.Skip("Mock server tests are disabled")
+ baseURL := "http://localhost:4010"
+ if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
+ baseURL = envURL
+ }
+ if !testutil.CheckTestServer(t, baseURL) {
+ return
+ }
+ client := kernel.NewClient(
+ option.WithBaseURL(baseURL),
+ option.WithAPIKey("My API Key"),
+ )
+ _, err := client.ProxyIPs.List(context.TODO(), kernel.ProxyIPListParams{
+ Country: kernel.String("country"),
+ Limit: kernel.Int(1),
+ Offset: kernel.Int(0),
+ Status: kernel.ProxyIPListParamsStatusActive,
+ })
+ if err != nil {
+ var apierr *kernel.Error
+ if errors.As(err, &apierr) {
+ t.Log(string(apierr.DumpRequest(true)))
+ }
+ t.Fatalf("err should be nil: %s", err.Error())
+ }
+}
diff --git a/shared/shared.go b/shared/shared.go
index 1d7ae0f..9c227d6 100644
--- a/shared/shared.go
+++ b/shared/shared.go
@@ -131,9 +131,11 @@ func (r *BrowserProfileParam) UnmarshalJSON(data []byte) error {
// determined based on the resolution (higher resolutions use lower refresh rates
// to keep bandwidth reasonable).
type BrowserViewport struct {
- // 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 int64 `json:"height" api:"required"`
- // 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 int64 `json:"width" api:"required"`
// Display refresh rate in Hz. Any positive integer is accepted; if omitted, GPU
// browsers default to 60 and other browsers derive it from width and height.
@@ -178,9 +180,11 @@ func (r BrowserViewport) ToParam() BrowserViewportParam {
//
// The properties Height, Width are required.
type BrowserViewportParam struct {
- // 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 int64 `json:"height" api:"required"`
- // 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 int64 `json:"width" api:"required"`
// Display refresh rate in Hz. Any positive integer is accepted; if omitted, GPU
// browsers default to 60 and other browsers derive it from width and height.