Dedicated IPs
A dedicated IP is a single address reserved exclusively for one subscription, instead of a shared location's pool of many instances. This page covers reading them: which addresses a subscription currently holds, how to connect to them, and where it may still reserve one.
This is not the Dedicated IP module. That module assigns, renews and backs up an address over an attested enclave protocol, and requires unlocking a subscription with restoreDips first. The methods here only read the addresses a subscription already has, from the same dataset as the rest of this module, and need no unlocking.
Reserving one of the available locations is the Simple Dedicated IP module (sdip).
A dedicated IP is not one of the locations returned by getLocationsForProtocols. It carries its own location, which need not be a location offered for regular connections, so it is never listed, recommended or speedtested alongside them.
get_dedicated_ips
Returns the dedicated IPs held by a subscription and the locations where it may reserve another.
This method reads the same full dataset as getFullLocationsForProtocols, so a caller that has already fetched it pays nothing extra. It refreshes over the network once the cache expires and so never returns stale data. A cached dataset is only reused for the subscription it was originally fetched for.
Nothing is filtered by protocol. A dedicated IP is one address, and which protocols it serves is decided by the service that owns it.
Parameters
| Name | Description |
|---|---|
| subscription_id | ID of the subscription which has a VPN entitlement, as described in Obtaining a VPN Subscription ID |
Returns
DedicatedIpsResult upon success, InstanceDiscoveryException otherwise.
An empty subscription_id throws InvalidInputParameters without any request. Any other exception means the whole locations dataset could not be read — you will have no locations or pecking rules either. It does not mean "no dedicated IPs"; that answer arrives inside DedicatedIps.
DedicatedIpsResult
| Name | Type | Description |
|---|---|---|
| dedicatedIps | DedicatedIps | The dedicated IP state for this subscription — see below |
| cacheState | CacheState | Fetched if retrieved over the network, Cached if served from a still-fresh cache. This method never returns Stale |
Handling the three answers
DedicatedIps has two variants, and the first of them covers two situations. All three need different handling.
| Answer | Meaning | What to show |
|---|---|---|
Ready, reserved non-empty | The subscription holds these addresses and they are connectable now | The addresses, each as its own connectable entry |
Ready, both lists empty | The subscription has no dedicated IP entitlement | Nothing — or an upsell. This is an ordinary answer, never an error |
Failed | The service that owns dedicated IPs could not be reached | Whatever you showed last. Both lists are unknown, not empty |
The distinction that matters is the last row. Failed and an empty Ready are easy to collapse into one "no dedicated IPs" screen, and doing so tells a paying user their address is gone during an outage that has not touched their subscription at all. Treat Failed as "cannot tell right now", keep the previous set on screen, and retry.
when (val ips = result.dedicatedIps) {
is DedicatedIps.Ready ->
if (ips.reserved.isEmpty()) showReservationPicker(ips.available)
else showHeldAddresses(ips.reserved)
is DedicatedIps.Failed ->
keepPreviousAndRetryLater() // do not clear the UI
}
switch result.dedicatedIps {
case let .ready(available, reserved):
reserved.isEmpty ? showReservationPicker(available) : showHeldAddresses(reserved)
case .failed:
keepPreviousAndRetryLater() // do not clear the UI
}
Retrying after a failure
While dedicated IPs are unavailable the server shortens the dataset's cache lifetime to one minute, down from an hour. Call the method again after that and it refetches, picking up the recovery without any explicit invalidation. Calls within the minute are served the cached failure and issue no request.
DedicatedIpsError carries the category. Unavailable is transient and worth retrying. Unknown is a category added after your build and should be treated exactly the same way.
DedicatedIps
| Variant | Fields | Description |
|---|---|---|
| Ready | available: Array of DedicatedIpLocation, reserved: Array of DedicatedIp | Both lists are known. Either may be empty |
| Failed | error: DedicatedIpsError | Neither list is known |
DedicatedIpsError
| Value | Description |
|---|---|
| Unavailable | Transient. Retrying later is worth it |
| Unknown | A category added after this build. Treat as Unavailable |
DedicatedIp
| Name | Type | Description |
|---|---|---|
| id | String | Stable identifier of the dedicated IP. Survives an address rotation, so key your own state on this rather than on the location or the address |
| location | DedicatedIpLocation | Where this address lives. Its id matches the available entry it was reserved from |
| endpoints | Array of EndpointConfiguration | One endpoint per protocol the address serves. The same type the rest of this module returns, so your existing connection code applies unchanged |
| ip | String | The address to show in the UI. Display only — the endpoints carry the addresses actually connected to |
DedicatedIpLocation
Shared by both lists: a held address's location carries the id of the available entry it was reserved from. This is not a ServerLocation id and must not be looked up among them.
| Name | Type | Description |
|---|---|---|
| id | String | Identifies the location across both lists |
| name | String | Display name |
| countryCode | String | ISO 3166-1 alpha-2 |
| latitude | Double | Latitude of the location |
| longitude | Double | Longitude of the location |
| availableCount | UInt32 | How many addresses are still reservable here. Zero on a held address's location means a second one cannot be taken there |