# API Reference

## `class VPNSDK: NSObject`

**`static func sdkVersion() -> String`**

Version of SDK.

**`var protocolType: VPNProtocolType`**

VPN protocol type of SDK.

**`var deviceID: String`**

Device ID in string representation.

**`var carrierID: String`**

Carrier ID provided to SDK config.

**`var isLoggedIn: Bool`**

Checks if user is logged in.

**`var token: String?`**

Current access token if user is logged in.

**`var state: VPNState`**

Current state of VPN connection.

**`var connectedDate: Date?`**

Date when VPN connection was established.

**`var connectedServerCountry: String?`**

Country code of connected VPN server

**`var connectedServerCity: String?`**

City name of connected VPN server

**`var remoteConfig: RemoteConfig?`**

Last received remote config. Can be `nil` if remote config wasn't successfully received yet.

**`var trafficCounters: TrafficCounters?`**

Local traffic counters. This property provides access to traffic usage statistics from the VPN connection.

The traffic counters are automatically stored for all protocols, including IPSec. This property will be populated when any of the following occurs:

* After initialization if you pass a non-nil value for `trafficCountersFetchInterval` parameter to the SDK configuration on init.
* After a successful call to `getTrafficCounters(completion:)` method.

Note that the counter data is maintained across sessions and automatically updated during active connections.

**Important**: Due to limitations in Apple's IPSec implementation, traffic counters are updated only through requests to the backend service. To prevent potential overload on the backend, updates are triggered based on a data consumption threshold of approximately 5MB. This means:

* Traffic counter updates may not appear immediately for small amounts of data transfer
* The VPN nodes send update events to the backend approximately every 5MB of consumed data
* During high load periods or reconnection spikes, updates may be even more infrequent
* This threshold value may be adjusted in future releases to optimize backend event processing

Additionally, there is a feature to introduce a \~5 second delay for batching events, which is currently disabled but could reduce backend load by 3-5x. This feature may be enabled in future releases to ensure scalability.

**`var lastTunnelError: VPNTunnelError?`**

Last error that occured in current/last app extension session. Always returns `nil` for `IPSecSDK` because app extension for this protocol is handled by Apple internally.

**`var isBypassEnabled: Bool`**

Checks is VPN in bypass mode.

**`var connectionFailureBehaviour: ConnectionFailureBehaviour?`**

Currect connection failure behaviour. If `nil` returned, it means that connection is started without any issues.

**`var clientNetworkList: ClientNetworkList?`**

Current CNL. SDK updates CNL as part of credentials loading.

**`var isIPInRFC1918Range: Bool`**

Indicates if the current device IP address falls into RFC1918 subnet range.

**`activatedStartPolicy: VPNStartPolicy?`**

Currently activated start policy.\
This property becomes non-nil after the start method is successfully called.\
Calling the stop method sets this value back to nil.

**`var lastStartedOnDemandConfiguration: OnDemandConfiguration?`**

The last on-demand configuration that was passed to the start method and was attempted to be saved to preferences.\
This property does not reflect the active on-demand configuration; it is only updated once during the start process.

**`func login(method: AuthMethod, completion: @escaping UserCompletion)`**

Logins and obtains `User` object that describes VPN user.\
Returns `User` on success.

**`func logout(completion: @escaping LogoutCompletion)`**

Logouts current user.

**`func currentUser(completion: @escaping UserCompletion)`**

Gets current user data from server.\
Returns `User` on success.

**`func virtualLocations(completion: @escaping VirtualLocationsCompletion)`**

Gets a list of countries that you can connect to.\
Returns `[VirtualLocation]` on success.

**`func installProfile(completion: @escaping ProfileCompletion)`**

Triggers iOS VPN subsystem to create/update VPN profile, showing user permission "Allow / Don't Allow" dialog.\
Calling this method is not required. Useful for custom tutorial implementation.\
**NOTE**: If you're using onDemand VPN feature, this installed profile **WILL** be triggered by system and VPN will be enabled.

**`func removeProfile(completion: @escaping ProfileCompletion)`**

Removes previous installed system VPN profile.\
**NOTE**: VPN services with different protocols can use different VPN profiles (e.g., Hydra and IPSec), and this method will remove **all** installed profiles related to app.

**`func loadCredentials(location: VirtualLocation?, proxy: VirtualLocation?, completion: @escaping CredentialsCompletion)`**

Gets credentials for specified location and proxy.\
Usually you don't want to call this method manually, because it's called automatically as part of start flow.\
Parameters:\\

* `location`: Virtual location provided by `virtualLocations(completion)` method. Pass `nil` or `.optimal()` to let SDK pick proxy automatically.\\
* `proxy`: Virtual location provided by `virtualLocations(completion)` method. Proxy allows to connect to multiple VPN servers in chain and provides extra layer of encryption and IP address masking. Currently supported only by Hydra, for other protocols this parameter will be ignored. Pass `nil` to disable proxy. Pass `.optimal()` to let SDK pick proxy automatically.\\
* `completion`: Handler that's called upon completion.\
  Returns `Credential` on success.

**`func fetchRemoteConfig(completion: @escaping RemoteConfigCompletion)`**

Gets remote config from server. Last loaded config is accessible through `remoteConfig` property.\
Returns `RemoteConfig` on success.

**`func start(location: VirtualLocation?, proxy: VirtualLocation?, policy: VPNStartPolicy, onDemandConfiguration: OnDemandConfiguration?, completion: @escaping StartStateCompletion)`**

Starts VPN with specified location and proxy.\
On first VPN connection, SDK will ask user to Allow or Deny VPN connection.\\

Parameters:\\

* `location`: Virtual location provided by `virtualLocations(completion)` method. Pass `nil` or `.optimal()` to let SDK pick proxy automatically.\\
* `proxy`: Virtual location provided by `virtualLocations(completion)` method. Proxy allows to connect to multiple VPN servers in chain and provides extra layer of encryption and IP address masking. Currently supported only by Hydra, for other protocols this parameter will be ignored. Pass `nil` to disable proxy. Pass `.optimal()` to let SDK pick proxy automatically.\\
* `policy`: Defines how the VPN should be started.\
  `connectNow`: Immediately establish a VPN connection when requested.\
  `configureOnDemand`: Prepare VPN settings but only connect when an On-Demand rule or condition triggers it (e.g., specific network or Wi-Fi SSID).
* `onDemandConfiguration`: On-demand behaviour configuration.\\
* `completion`: Handler that's called upon completion.\
  Returns `Credential` on success.

**`func stop(completion: @escaping StateCompletion)`**

Stops connected VPN.

**`func getTrafficCounters(completion: @escaping TrafficCountersCompletion)`**

Gets current traffic counters from server.\
Returns `TrafficCounters` on success.

**`func remainingTraffic(completion: @escaping RemainingTrafficCompletion)`**

Gets current traffic limits from server.\
Returns `RemainingTraffic` on success.

**`func purchase(purchaseToken: String?, type: String, completion: @escaping PurchaseCompletion)`**

Validates purchase on server and updates user data that related to subscription (e.g., limits).\
Returns `Purchase` on success.

### `class HydraSDK: VPNSDK`

**`init(configuration: HydraConfiguration, completionQueue: DispatchQueue)`**

Designated initializer. SDK instance should be a singleton instance.\
Use `HydraConfiguration` type instance to initialize `HydraSDK`.\
Specify `completionQueue` to receive callbacks for all async methods on this queue. Default is `DispatchQueue.main`

**`var configuration: HydraConfiguration`**

Passed Hydra configuration.

**`func applyLocationIfConnected(_ newLocation: VirtualLocation?, completion: @escaping ApplyLocationCompletion)`**

This function switches the location in the active network extension without killing and restarting it. It returns an error if the VPN is not currently connected. Changing the Virtual Location without killing the active network extension is supported only for Hydra and WireGuard protocols.

**Note:**

When requesting an optimal location while the VPN is already connected, there is a limitation in the VPN architecture: the optimal location selection is performed from within the VPN tunnel itself, which may result in a location that is not truly optimal based on your actual geo-IP location.

**Workaround:** To ensure you get the truly optimal location based on your real geo-IP, stop the VPN connection first and then establish a new connection with the optimal location parameter.

**Warning:**

* The `applyLocationIfConnected` function will throw an error when used with the IPSec protocol. It is designed to work only with Hydra and WireGuard protocols.
* It's important to note that iOS and macOS may have leaks by default, potentially exposing the device's real IP address even when the VPN tunnel is active. To prevent such leaks, set the includeAllNetworks flag to true. This ensures that all network interfaces are routed through the VPN, blocking any potential leaks through other interfaces. Setting `includeAllNetworks = true` is the only way to guarantee that no IP leaks occur while the tunnel is active.

**`func updateConfiguration(_ configuration: HydraConfiguration) throws`**

Updates Hydra configuration without creating a new instance of SDK. Configuration can't be updated if the connection is started, you need to call `stopVPN` function before updating configuration, otherwise `VPNSDKError.updateWhileConnected` error will be thrown. Please note if you want to change the main parameters of configuration (`hostURL`, `carrierID`, `extensionBundleID`, `groupData`), you need to create new instance `HydraSDK` with this configuration, otherwise `VPNSDKError.configurationMismatch` error will be thrown.

### `struct OnDemandConfiguration`

#### `isEnabled`

Enables On Demand VPN feature. VPN will be triggered automatically by the System after `startVPN` is triggered.

**Note:** The SDK automatically disables On Demand functionality when calling `stop()` to ensure explicit VPN control. When you call `stop()` on the SDK, it sets `isOnDemandEnabled` to `false` and saves this configuration to system preferences, preventing automatic reconnection based on On Demand rules.

If VPN connection could not be established because of network environment or interrupted by out of traffic error code, then VPN will switch to bypass mode automatically until user reconnects VPN from main application, VPN icon will not be visible in the status bar.

For advanced On Demand configuration and workarounds to maintain persistent On Demand behavior, see the [Reconnection strategy](/paas/sdk/unified-vpn-sdk-for-apple/features/reconnection-strategy.md).

#### `onDemandRules`

On demand rules to be used for the VPN connection.

### `struct NetworkConfiguration`

**`tunnelDNSServers: [String]?`**

Your preferred DNS servers to use. If not set, a default ones will be used. Should be in format xxx.xxx.xxx.xxx (eg. 1.1.1.1).

**`disconnectOnSleep: Bool?`**

If `true`, the VPN connection will be disconnected when the device goes to sleep, by default set to `false`.

**`includeAllNetworks: Bool`**

Forces all network traffic through the VPN tunnel to prevent IP leaks. When set to `true`, the system routes all network interfaces through the VPN, ensuring no traffic bypasses the tunnel. This is the only way to guarantee that no IP leaks occur while the tunnel is active. Default is `false`.

**`excludeLocalNetworks: Bool`**

Excludes local network traffic from VPN routing when `includeAllNetworks` is set to `true`. This allows devices to communicate with local resources (e.g., printers, file servers, local network devices using RFC1918 addresses like 192.168.x.x, 10.x.x.x, 172.16.x.x) while maintaining VPN protection for internet traffic. Only takes effect when `includeAllNetworks` is `true`. Default is `false`.

**Requirements:**

* iOS 14.2+ for both flags
* Not available on tvOS

**Common configurations:**

* `includeAllNetworks: false, excludeLocalNetworks: false` - Standard VPN behavior
* `includeAllNetworks: true, excludeLocalNetworks: false` - Maximum security, all traffic through VPN
* `includeAllNetworks: true, excludeLocalNetworks: true` - Balanced security with local network access

### `struct BypassConfiguration`

Enumeration that defines different bypass behaviours for VPN usage.

**`isFullBypassForced: Bool = false`**

Forces **full bypass** mode. Defaults to `false`. If `true`, all traffic is bypassed and not routed through the VPN.

**`bypassDomainsBehaviour: VPNApplicationSDK.BypassConfiguration.BypassBehaviour`**

A behaviour that is applied to the passed `bypassDomains`.

* `.bypass`: Treats bypassDomains as an exclusion list. Traffic to domains matching the list is routed outside the VPN tunnel via the device's default network interface; everything else is tunneled.
* `.bypassAllExcept`: Inverts the meaning of the list. Traffic to domains matching bypassDomains is routed through the VPN; all other traffic bypasses the tunnel. This corresponds to the "Domain route via VPN" / split-include feature.

**`bypassDomains: [String]?`**

A list of domains to bypass VPN. Wildcards accepted.\
Example: `["*google.com"]` means that Google domain and it's subdomains will be accessed directly, without VPN.

**`bypassDNSServer: String?`**

A DNS server to bypass VPN. Should be in the format `xxx.xxx.xxx.xxx` (eg. 1.1.1.1).

### `struct ModulesConfiguration`

**`debugLogging: Bool`**

Enables or disables debug logging. **Don't forget to disable for release build!**

**`isAnalyticsEnabled: Bool`**

Enables or disables internal event tracking (like start, stop, etc.).

**`isClientListEnabled: Bool`**

Indicates will CNL functionality take part in VPN connection logic.

**`isVPNProtocolLabelEnabled: Bool`**

Indicates VPN Protocol Label will be postfixed to the profile name or not.

**`extensionConfigLoadTimeout: Int`**

Sets timeout period for network extension credentials verification/loading

### `struct HydraConfiguration`

**`carrierID: String`**

Your unique service identifier.

**`extensionBundleID: String`**

Network Extension target's Bundle Identifier.

**`groupData: VPNGroupData`**

App group info that is used for data sharing.

**`hostURLs`**

Hosts that will be used as static backed urls.

**`profileName: String`**

Sets the name for VPN profile that is visible in iOS Settings > General > VPN (Title of profile, subtitle will always be the application name).

**`serverAddressDisplayName: String?`**

Sets the name for VPN server address that is visible in iOS Settings > General > VPN (Server field).

**`isVPNIconFixEnabled: Bool`**

Enables fixing of VPN Icon (LTE + VPN when on Wi-Fi) when it detects that it's broken.

#### `onDemandConfiguration`

On Demand behaviour configuration.\
This parameter is deprecated and will be removed in future versions.\
Use the `onDemandConfiguration` parameter in the `start` method instead.

#### `networkConfiguration`

Network configuration.

#### `bypassConfiguration`

Bypass mode configuration.

#### `modulesConfiguration`

Modules configuration.

**`deviceType: String?`**

If value is `nil`, device type will be detected automatically. Otherwise provided value will be used. This string can be used as a parameter for some network requests.

**`logsCryptographicCredentials`**

Optional value of `CryptographicCredentials` to encode logs. If value is`nil` default credentials will be used.

**`externalDeviceID: String?`**

Optional value to override the device id. If not provided will be generated by the SDK internally.

**`systemExtensionEncryptionKey: SymmetricKey?`**

Custom encryption key for system extension. It has no effect in a non-system extension environment.

### `class IPSecSDK: VPNSDK`

**`init(configuration: IPSecConfiguration, completionQueue: DispatchQueue)`**

Designated initializer. SDK instance should be a singleton instance.\
Use `IPSecConfiguration` type instance to initialize `IPSecSDK`.\
Specify `completionQueue` to receive callbacks for all async methods on this queue. Default is `DispatchQueue.main`

#### `func updateConfiguration(_ configuration: IPSecConfiguration) throws`

Updates IPSec configuration without creating a new instance of SDK. Configuration can't be updated if the connection is started, you need to call `stopVPN` function before updating configuration, otherwise `VPNSDKError.updateWhileConnected` error will be thrown. Please note if you want to change the main parameters of configuration (`hostURL`, `carrierID`, `extensionBundleID`, `groupData`), you need to create new instance `IPSecSDK` with this configuration, otherwise `VPNSDKError.configurationMismatch` error will be thrown.

### `struct IPSecConfiguration`

**`carrierID: String`**

Your unique service identifier.

**`groupData: VPNGroupData`**

App group info that is used for data sharing. Though the `IPSecSDK` does not use the extension directly, you may still want to provide this value in order to ensure that the preserved data remains readable across different protocols.

**`trafficCountersFetchInterval: TimeInterval?`**

Interval that will be used for timer that fetches traffic counters periodically and write it to `trafficCounters` property of SDK instance. Pass `nil` to disable the timer.

**`hostURLs`**

Hosts that will be used as static backed urls.

**`profileName: String`**

Sets the name for VPN profile that is visible in iOS Settings > General > VPN (Title of profile, subtitle will always be the application name).

#### `onDemandConfiguration`

On Demand behaviour configuration.\
This parameter is deprecated and will be removed in future versions.\
Use the `onDemandConfiguration` parameter in the `start` method instead.

#### `networkConfiguration`

Network configuration.

#### `bypassConfiguration`

Bypass mode configuration.

#### `modulesConfiguration`

Modules configuration.

**`deviceType: String?`**

If value is `nil`, device type will be detected automatically. Otherwise provided value will be used. This string can be used as a parameter for some network requests.

**`logsCryptographicCredentials`**

Optional value of `CryptographicCredentials` to encode logs. If value is`nil` default credentials will be used.

**`externalDeviceID`**

Optional value to override the device id. If not provided will be generated by the SDK internally.

**`storageServiceName`**

Optional value for service name that is used for storing password inside keychain.

**`systemExtensionEncryptionKey`**

Custom encryption key for system extension. It has no effect in a non-system extension environment. Though the `IPSecSDK` does not use the extension directly, you may still want to provide this value in order to ensure that the preserved data remains readable across different protocols.

### `class WireguardSDK: VPNSDK`

**`init(configuration: WireguardConfiguration, completionQueue: DispatchQueue)`**

Designated initializer. SDK instance should be a singleton instance.\
Use `WireguardConfiguration` type instance to initialize `WireguardSDK`.\
Specify `completionQueue` to receive callbacks for all async methods on this queue. Default is `DispatchQueue.main`

**`func setSessionPingInterval(_ newValue: TimeInterval?, completion: @escaping (Error?) -> Void)`**

Changes Wireguard session ping interval if VPN is connected. Returns error if VPN is not currently connected.

#### `func updateConfiguration(_ configuration: WireguardConfiguration) throws`

Updates Wireguard configuration without creating a new instance of SDK. Configuration can't be updated if the connection is started, you need to call `stopVPN` function before updating configuration, otherwise `VPNSDKError.updateWhileConnected` error will be thrown. Please note if you want to change the main parameters of configuration (`hostURL`, `carrierID`, `extensionBundleID`, `groupData`), you need to create new instance `WireguardSDK` with this configuration, otherwise `VPNSDKError.configurationMismatch` error will be thrown.

### `struct WireguardConfiguration`

**`carrierID: String`**

Your unique service identifier.

**`extensionBundleID: String`**

Network Extension target's Bundle Identifier.

**`groupData: VPNGroupData`**

App group info that is used for data sharing.

**`hostURLs`**

Hosts that will be used as static backed urls.

**`profileName: String`**

Sets the name for VPN profile that is visible in iOS Settings > General > VPN (Title of profile, subtitle will always be the application name).

**`sessionPingInterval: TimeInterval?`**

Enables or disables internal event tracking (like start, stop, etc.). Fixed interval that will be used by timer that checks session state. If there is any error received during verification (for example, traffic exceeded), session will be closed with `VPNTunnelError.invalidSession` or `VPNTunnelError.trafficExceeded` error. When `nil` is passed, interval will be determined depending on session TTL.

**`serverAddressDisplayName: String?`**

Sets the name for VPN server address that is visible in iOS Settings > General > VPN (Server field).

#### `onDemandConfiguration`

On Demand behaviour configuration.\
This parameter is deprecated and will be removed in future versions.\
Use the `onDemandConfiguration` parameter in the `start` method instead.

#### `networkConfiguration`

Network configuration.

#### `bypassConfiguration`

Bypass mode configuration.

#### `modulesConfiguration`

Modules configuration.

**`deviceType: String?`**

If value is `nil`, device type will be detected automatically. Otherwise provided value will be used. This string can be used as a parameter for some network requests.

**`logsCryptographicCredentials`**

Optional value of `CryptographicCredentials` to encode logs. If value is`nil` default credentials will be used.

**`externalDeviceID`**

Optional value to override the device id. If not provided will be generated by the SDK internally.

**`systemExtensionEncryptionKey`**

Custom encryption key for system extension. It has no effect in a non-system extension environment.

## `class ComposedVPNSDK: NSObject`

**`var activeProtocolType: VPNProtocolType`**

VPN protocol type of active SDK.

**`var deviceID: String`**

Device ID in string representation.

**`var carrierID: String`**

Carrier ID provided to SDK.

**`var isLoggedIn: Bool`**

Checks if user is logged in.

**`var token: String?`**

Current access token if user is logged in.

**`var state: VPNState`**

Current state of VPN connection.\
Gets corresponding property value from active SDK.

**`var connectedDate: Date?`**

Last connected date of active SDK.

**`var remoteConfig: RemoteConfig?`**

Last received remote config. Can be `nil` if remote config wasn't successfully received yet.

**`var trafficCounters: TrafficCounters?`**

Local traffic counters of active SDK.

**`var isBypassEnabled: Bool`**

Checks is VPN in bypass mode.

**`var connectionFailureBehaviour: ConnectionFailureBehaviour?`**

Currect connection failure behaviour. If `nil` returned, it means that connection is started without any issues.

**`var clientNetworkList: ClientNetworkList?`**

Current CNL. SDK updates CNL as part of credentials loading.

**`var isIPInRFC1918Range: Bool`**

Indicates if the current device IP address falls into RFC1918 subnet range.

**`var hydraConfiguration: HydraConfiguration?`**

Configuration of HydraSDK.

**`lastTunnelError(for protocolType: VPNProtocolType?) -> VPNTunnelError?`**

Last error that occured in current/last app extension session for specified protocol type.\
If `protocolType` is `nil` returns error for active protocol type.\
Always returns `nil` when `protocolType` is `ipsec` because app extension for this protocol is handled by Apple internally.

**`activatedStartPolicy: VPNStartPolicy?`**

Currently activated start policy.\
This property becomes non-nil after the start method is successfully called.\
Calling the stop method sets this value back to nil.

**`var lastStartedOnDemandConfiguration: OnDemandConfiguration?`**

The last on-demand configuration that was passed to the start method and was attempted to be saved to preferences.\
This property does not reflect the active on-demand configuration; it is only updated once during the start process.

**`func login(method: AuthMethod, completion: @escaping UserCompletion)`**

Logins and obtains `User` object that describes VPN user. Login is shared between VPN SDKs with different protocols.\
Returns `User` on success.

**`func logout(completion: @escaping LogoutCompletion)`**

Logouts current user.

**`func currentUser(completion: @escaping UserCompletion)`**

Gets current user data from server.\
Returns `User` on success.

**`func virtualLocations(completion: @escaping VirtualLocationsCompletion)`**

Gets a list of countries that you can connect to.\
Returns `[VirtualLocation]` on success.

**`func installProfile(completion: @escaping ProfileCompletion)`**

Triggers iOS VPN subsystem to create/update VPN profile, showing user permission "Allow / Don't Allow" dialog.\
Calling this method is not required. Useful for custom tutorial implementation.\
**NOTE**: If you're using onDemand VPN feature, this installed profile **WILL** be triggered by system and VPN will be enabled.

**`func removeProfile(completion: @escaping ProfileCompletion)`**

Removes previous installed system VPN profile.\
**NOTE**: VPN services with different protocols can use different VPN profiles (e.g., Hydra and IPSec), and this method will remove all installed profiles related to app.

**`func loadCredentials(location: VirtualLocation?, proxy: VirtualLocation?, completion: @escaping CredentialsCompletion)`**

Gets credentials for specified location and proxy.\
Usually you don't want to call this method manually, because it's called automatically as part of start flow.\
Parameters:\\

* `location`: Virtual location provided by `virtualLocations(completion)` method. Pass `nil` or `.optimal()` to let SDK pick proxy automatically.\\
* `proxy`: Virtual location provided by `virtualLocations(completion)` method. Proxy allows to connect to multiple VPN servers in chain and provides extra layer of encryption and IP address masking. Currently supported only by Hydra, for other protocols this parameter will be ignored. Pass `nil` to disable proxy. Pass `.optimal()` to let SDK pick proxy automatically.\\
* `completion`: Handler that's called upon completion.\
  Returns `Credential` on success.

**`func fetchRemoteConfig(completion: @escaping RemoteConfigCompletion)`**

Gets remote config from server. Last loaded config is accessible through `remoteConfig` property.\
Returns `RemoteConfig` on success.

**`func start(location: VirtualLocation?, proxy: VirtualLocation?, policy: VPNStartPolicy, onDemandConfiguration: OnDemandConfiguration?, completion: @escaping StartStateCompletion)`**

Starts VPN with specified location and proxy.\
On first VPN connection, SDK will ask user to Allow or Deny VPN connection.\\

Parameters:\\

* `location`: Virtual location provided by `virtualLocations(completion)` method. Pass `nil` or `.optimal()` to let SDK pick proxy automatically.\\
* `proxy`: Virtual location provided by `virtualLocations(completion)` method. Proxy allows to connect to multiple VPN servers in chain and provides extra layer of encryption and IP address masking. Currently supported only by Hydra, for other protocols this parameter will be ignored. Pass `nil` to disable proxy. Pass `.optimal()` to let SDK pick proxy automatically.\\
* `policy`: Defines how the VPN should be started.\
  `connectNow`: Immediately establish a VPN connection when requested.\
  `configureOnDemand`: Prepare VPN settings but only connect when an On-Demand rule or condition triggers it (e.g., specific network or Wi-Fi SSID).
* `onDemandConfiguration`: On-demand behaviour configuration.\\
* `completion`: Handler that's called upon completion.\
  Returns `Credential` on success.

**`func stop(completion: @escaping StateCompletion)`**

Stops connected VPN.

**`func getTrafficCounters(completion: @escaping TrafficCountersCompletion)`**

Gets current traffic counters from server.\
Returns `TrafficCounters` on success.

**`func remainingTraffic(completion: @escaping RemainingTrafficCompletion)`**

Gets current traffic limits from server.\
Returns `RemainingTraffic` on success.

**`func purchase(purchaseToken: String?, type: String, completion: @escaping PurchaseCompletion)`**

Validates purchase on server and updates user data that related to subscription (e.g., limits).\
Returns `Purchase` on success.

**`func applyLocationIfHydraConnected(_ newLocation: VirtualLocation?, completion: @escaping ApplyLocationCompletion)`**

Switches location in the active network extension (without killing it and starting new one).\
Returns error if VPN is not currently connected.\
**NOTE**: Does nothing if Hydra isn't active protocol.

**`func setWireguardSessionPingInterval(_ newValue: TimeInterval?, completion: @escaping (Error?) -> Void)`**

Changes Wireguard session ping interval if VPN is connected. Returns error if VPN is not currently connected. Does nothing if Wireguard isn't active protocol.

**`func updateHydraConfiguration(_ configuration: HydraConfiguration) throws`**

Updates Hydra configuration without creating a new instance of HydraDSK.\
**NOTE** Configuration can't be updated if the connection is started, you need to call `stopVPN` function before updating configuration, otherwise `VPNSDKError.notPermitted` error will be thrown.\
Please note if you want to change the main parameters of configuration (`carrierID`, `extensionBundleID`, `groupData`), you need to create new instance `HydraSDK` with this configuration, otherwise `VPNSDKError.configurationMismatch` error will be thrown.

**`func updateIPSecConfiguration(_ configuration: IPSecConfiguration) throws`**

Updates IPSec configuration without creating a new instance of SDK. Configuration can't be updated if the connection is started, you need to call `stopVPN` function before updating configuration, otherwise `VPNSDKError.updateWhileConnected` error will be thrown. Please note if you want to change the main parameters of configuration (`hostURL`, `carrierID`, `extensionBundleID`, `groupData`), you need to create new instance `IPSecSDK` with this configuration, otherwise `VPNSDKError.configurationMismatch` error will be thrown.

**`func updateWireGuardConfiguration(_ configuration: WireguardConfiguration) throws`**

Updates Wireguard configuration without creating a new instance of SDK. Configuration can't be updated if the connection is started, you need to call `stopVPN` function before updating configuration, otherwise `VPNSDKError.updateWhileConnected` error will be thrown. Please note if you want to change the main parameters of configuration (`hostURL`, `carrierID`, `extensionBundleID`, `groupData`), you need to create new instance `WireguardSDK` with this configuration, otherwise `VPNSDKError.configurationMismatch` error will be thrown.

#### `func updateConfiguration(_ configuration: ComposedConfiguration) throws`

Updates Composed configuration without creating a new instance of SDK. Configuration can't be updated if the connection is started, you need to call `stopVPN` function before updating configuration, otherwise `VPNSDKError.updateWhileConnected` error will be thrown. Please note if you want to change the main parameters of configuration (`hostURL`, `carrierID`, `extensionBundleID`, `groupData`), you need to create new instance `ComposedVPNSDK` with this configuration, otherwise `VPNSDKError.configurationMismatch` error will be thrown.

### `class ManualSwitchingVPNSDK: ComposedVPNSDK`

**`init(configuration: ComposedConfiguration, initialProtocolType: VPNProtocolType, completionQueue: DispatchQueue)`**

Designated initializer. SDK instance should be a singleton instance.\
Use `ComposedConfiguration` type instance to initialize `ManualSwitchingVPNSDK`.\
Use `initialProtocolType` parameter to specify what VPN protocol should be active right after inititalization.\
Specify `completionQueue` to receive callbacks for all async methods on this queue. Default is `DispatchQueue.main`

**`func switchToProtocol(_ newProtocolType: VPNProtocolType, completion: ((_ error: Error?, _ activeSDK: VPNSDK?) -> Void)?)`**

Switches VPN procolol type by user requirement. If VPN is connected at the moment of call, it will be stopped and then reconnected to the same location after protocol change.\
Returns new active SDK on success.

## `class AutoSwitchingVPNSDK: ComposedVPNSDK`

**`init(manualSwitchingSDK: ManualSwitchingVPNSDK, priorityProvider: @escaping PriorityProvider)`**

Designated initializer. SDK instance should be a singleton instance.\
Use `ManualSwitchingVPNSDK` instance with corresponding config to initialize `AutoSwitchingVPNSDK`.\
Use `priorityProvider` parameter to specify which VPN protocol priority will be used during start flow.

### `struct ComposedConfiguration`

**`availableTypes: ComposedConfiguration.SDKType`**

Available VPN protocols that will be used by Composed SDK. At least two different protocols should be provided.

**`carrierID: String`**

Your unique service identifier.

**`groupData: VPNGroupData`**

App group info that is used for data sharing.

**`trafficCountersFetchInterval: TimeInterval?`**

Interval that will be used for timer that fetches traffic counters periodically and write it to `trafficCounters` property of SDK instance. Pass `nil` to disable the timer. Works only for active SDKs that can't provide traffic counters directly from tunnel provider (e.g. IPSec).

**`hostURLs`**

Hosts that will be used as static backed urls.

**`profileName: String`**

Sets the name for VPN profile that is visible in iOS Settings > General > VPN (Title of profile, subtitle will always be the application name).

**`wireguardSessionPingInterval: TimeInterval?`**

Fixed interval that will be used by timer that checks wireguard session state. If there is any error received during verification (for example, traffic exceeded), session will be closed with `VPNTunnelError.invalidSession` or `VPNTunnelError.trafficExceeded` error. When `nil` is passed, interval will be determined depending on session TTL.

**`serverAddressDisplayName: String?`**

Sets the name for VPN server address that is visible in iOS Settings > General > VPN (Server field).

#### `onDemandConfiguration`

On Demand behaviour configuration.\
This parameter is deprecated and will be removed in future versions.\
Use the `onDemandConfiguration` parameter in the `start` method instead.

#### `networkConfiguration`

Network configuration.

#### `bypassConfiguration`

Bypass mode configuration.

#### `modulesConfiguration`

Modules configuration.

**`isVPNIconFixEnabled: Bool`**

Enables fixing of VPN Icon (LTE + VPN when on Wi-Fi) when it detects that it's broken.

**`deviceType: String?`**

If value is `nil`, device type will be detected automatically. Otherwise provided value will be used. This string can be used as a parameter for some network requests.

**`logsCryptographicCredentials`**

Optional value of `CryptographicCredentials` to encode logs. If value is`nil` default credentials will be used.

**`externalDeviceID`**

Optional value to override the device id. If not provided will be generated by the SDK internally.

**`systemExtensionEncryptionKey`**

Custom encryption key for system extension. It has no effect in a non-system extension environment.

**`storageServiceName`**

Optional value for service name that is used for storing password inside keychain.

### `struct VPNGroupData`

Represents app group information that is used for data sharing.

**`groupID: String`**

App Group ID that is created for the current application.

**`usesSystemExtension: Bool`**

Pass `true` if you use system network extension on macOS.\
Pay attention that:\\

* Shared user folder will be used for data storing in this case, but `groupID` should be provided anyway, that will provide unique folder name.\\
* `App sandbox` capability should be disabled.

## `struct AuthMethod`

**`init(type: AuthMethodType, token: String?)`**

Main initializer for creating an authentication method.

### `enum AuthMethodType`

**`case pango`**

Pango Auth authentication method (Recommended). Use the access token obtained from Pango Auth sign-in. Provide it to AuthMethod init function like this: `AuthMethod(type: .pango, token: "PANGO_ACCESS_TOKEN")`

**`case oauth`**

OAuth authentication method (Alternative). For partners with existing OAuth infrastructure. OAuth flow should be implemented by your application. After finishing OAuth flow and obtaining OAuth access token, provide it to AuthMethod init function like this: `AuthMethod(type: .oauth, token: "OAUTH_TOKEN")`

**`case facebook`**

Authenticate with Facebook SDK.

**`case google`**

Authenticate with Google SDK.

**`case twitter`**

Authenticate with Twitter SDK.

**`case github`**

Authenticate with GitHub SDK.

**`case firebase`**

Authenticate with Firebase SDK.

**`case custom(String)`**

Custom auth. If you are using custom authentication scheme, use this case.

## `struct User`

Describes VPN user.

**`let accessToken: String?`**

VPN SDK access token.

**`let subscriber: Subscriber`**

User's subscription information.

## `struct Subscriber`

Describes user's subscription information.

**`let subscriberID: Int`**

Subscriber identifier.

**`let activatedDevices: Int`**

Subscriber activated devices.

**`let activeSessions: Int`**

Subscriber active sessions.

**`let name: String`**

Subscriber name.

**`let extref: String`**

**`let carrierID: String`**

Subscriber carrier ID.

**`let bundle: Bundle`**

Subscription bundle.

**`let socialProfiles: [String: String]`**

Subscriber hash of social profiles with information.

**`let purchases: [SubscriberPurchase]`**

Array of subscriber purchases.

## `struct Bundle`

Describes subscription bundle information.

**`let licenseName: String`**

Name of user's license.

**`let bundleID: Int`**

Name of a purchased bundle.

**`let devicesLimit: Int`**

Number of devices limit.

**`let sessionsLimit: Int`**

Number of sessions limit.

## `struct SubscriberPurchase`

Describes subscription information.

**`let id: Int`**

Subscription identifier.

**`let type: String`**

Subscription type on server.

**`let time: Date`**

Date of last subscription validation date. Usually server validates subscription 1 time per day.

**`let isActive: Bool`**

Checks is subscription currently valid and active.

## `struct VirtualLocation`

Describes VPN server location information.

**`let type: LocationType`**

Location type from server: standard location, private group or profile.

**`let name: String?`**

Location name from server.

**`let description: String?`**

Location description from server.

**`let privateGroup: String?`**

Name of private server group name (can be empty).

**`let subdivision: String?`**

Subdivision name if provided.

**`let city: String?`**

City name if provided.

**`let countryCode: String?`**

Country location code if provided.

**`let country: String?`**

Country description based on country code.

**`let isAvailable: Bool`**

Determines could location be used.

**`let isOptimal: Bool`**

Determines is location optimal.

**`let isPrivate: Bool`**

Determines is location private.

**`let title: String?`**

Location's more suitable title.

**`static func optimal() -> VirtualLocation`**

Creates optimal location.

## `struct TrafficCounters`

**`let received: UInt64`**

Bytes received in current session.

**`let transmitted: UInt64`**

Bytes transmitted in current session.

## `struct RemainingTraffic`

Represents traffic limits information.

**`let sessionStartTime: UInt64`**

UNIX timestamp when current session was started.

**`let trafficUsageLimit: UInt64`**

Amount of bytes available to current User.

**`let trafficUsed: UInt64`**

Amount of bytes user utilized.

**`let trafficRemaining: UInt64`**

Amount of bytes that is available to User.

## `protocol BaseNetworkExtensionDelegate`

Your app's Network Extension provider must implement this protocol. You can override methods from this protocol in order to be able to track certain actions like VPN start or errors inside Network Extension.

**`func vpnWillStart(with options: StartupOptions)`**

Called right before VPN start attempt.

```swift
public struct StartupOptions {
    public let isAppStart: Bool
    public let isOnDemand: Bool
    public let isStartedFromSleep: Bool

    /// ConnectionFailureBehaviour that is selected for the current start attempt. `nil` means success
    public let failureBehaviour: ConnectionFailureBehaviour?

    /// Errors from the previous on-demand sessions
    public let lastOnDemandConnectionErrors: [VPNTunnelError]
}
```

Options that can be applied to `vpnWillStart` function as call conditions.

**`func vpnDidStart()`**

Called after successful VPN start.

**`func vpnWillStop(withError error: VPNTunnelError?, availableRestartCompletion: ((_ shouldRestart: Bool) -> Void)?)`**

This method will be called with non nil `availableRestartCompletion` parameter if VPN is about to stop with an error. In this case until completion closure will be called, the extension will be in killswitch feature (no out/in going network packets will be delivered/received). If VPN is about to stop without any error, then this method will be called with nil `availableRestartCompletion` without killswitch feature. Parameter `error`: Tunnel error that caused stop. `nil` value means user initiated stop. Parameter `availableRestartCompletion` - if it's not nil, pass `true` to the completion block if you want to restart the VPN extension without killing and using the same delegate object, otherwise, the new delegate object will be created.

**`func vpnWillGoToSleep()`**

Called when current vpn session is going to sleep because of OS requirement.

**`func vpnWillWakeUpFromSleep()`**

Called when vpn session was waked up from sleep.

**`func vpnDidReceiveError(_ error: VPNTunnelError)`**

Called when VPN error occured. Do not call long-running async operations here as the process will shut down.

**`func vpnDidReceiveTrafficCounters(_ counters: TrafficCounters)`**

Called when VPN traffic counters did update.

**`func fetchSystemExtensionEncryptionKey(completionHandler: escaping (Result<SymmetricKey?, Error>) -> Void`**

Called once as a part of the system extension start flow to get a custom encryption key. The same key should be provided to the SDK configuration on the app side.

`.success(nil)` - extension will proceed with default encryption key

`.success(.some(...))` - extension will proceed with passed encryption key

`.failure(...)` - not possible to fetch the key, extension will stop with error

Default implementation immediately calls `completionHandler` with `.success(nil)`.

### `enum VPNSDKError`

Reflects various errors that can be thrown by SDK operations.

**`case emptyToken = 0`**

Token is required for operation, but it's missing.

**`case invalidToken = 1`**

Saved token is invalid.

**`case alreadyConnected = 2`**

VPN is already connected.

**`case inProgress = 3`**

Operation is already in progress.

**`case notConnected = 4`**

VPN status isn't connected but it's required by operation.

**`case loginWhileConnected = 5`**

Login attempt while VPN is connected.

**`case logoutWhileConnected = 6`**

Logout attempt while VPN is connected.

**`case notPermitted = 7`**

Operation isn't permitted by SDK.

**`case configurationMismatch = 8`**

Static configuration properties were changed during dynamic reconfiguring.

**`case invalidConnection = 9`**

Received connection data isn't valid.

**`case timeout = 10`**

Connection start timeouted.

**`case emptyValue = 11`**

Value is empty.

**`case updateWhileConnected = 12`**

Update attempt while VPN is connected.

### `enum PartnerAPI.APIError`

Reflects errors that can be thrown by operations with network call.

**`case unauthorized = 104`**

This user is unauthorized or login operation is still pending.

**`case notAuthorized = 112`**

The token of user is expired.

**`case vpnServerUnavailable = 106`**

Selected server or country code is not available.

**`case userSuspended = 105`**

This user is suspended.

**`case sessionExceed = 102`**

Amount of allowed sessions for this user is exceed.

**`case trafficExceed = 103`**

Amount of allowed traffic for this user is exceed.

**`case internalServerError = 107`**

Server was unable to fetch credentials for this country code.

**`case deviceExceed = 108`**

The amount of allowed devices for this user is exceed.

**`case invalidPurchase = 110`**

The purchase could be validated.

**`case unknownServerResponse = 111`**

This response could mean you don't have latest VPN SDK. Please report to developers.

**`case badRequest(message: String?) = 113`**

Bad request server error.

**`case failedResult(resultString: String) = 114`**

Result in server response wasn't successful, but error is unknown.

**`case networkError(Error) = 109`**

Internet connection is not available or network request has failed. Feel free to try again.

**`case invalidCredentials = 115`**

Credentials verification failed.

**`case sessionNotFound = 116`**

Session with the specified ID doesn't exist on server or it's expired.

**`case nextHopUnavailable = 117`**

One of Personal Bridge URLs is invalid.

**`case forbidden = 118`**

Request is not allowed.

**`case notAnExitNode = 119`**

Personal Bridge next\_hops is empty.

**`case tooManyHops = 120`**

Number of next\_hops bigger then configured limit.

**`case hopNotAllowed = 121`**

One of next\_hops is not allowed to connect.

### `enum VPNTransportError`

Reflects errors that can be thrown by VPN transport operations (like start, stop, app message sending, etc.).

**`case statusChangedToInvalid = 1`**

Incorrect VPN status sequence.

**`case canceled = 2`**

Connection attempt was canceled.

**`case unknown = 3`**

Unknown error.

**`case connectFailed = 4`**

General connection attempt error if nothing was reported by tunnel provider.

**`case startInProgress = 5`**

Start is already in progress.

**`case stopInProgress = 6`**

Stop is already in progress.

**`case timeout = 7`**

Connection attempt timeout.

**`case wrapped(Error) = 8`**

Wrapped error (usually from NetworkExtension framework)

**`case tunnelError(VPNTunnelError) = 9`**

Error reported by tunnel provider.

**`case rateLimit = 10`**

App messages rate limit reached.

**`case notConnected = 11`**

VPN status isn't connected but it's required by operation.

**`case notReady = 12`**

SDK is not ready to receive app message.

**`case unableToEncodeMessage = 13`**

Failed to encode app message.

**`case emptyData = 14`**

Received app message data is empty.

**`case unableToDecodeResponse = 15`**

Failed to decode app message.

**`case appMessageFailureResult(reason: String) = 16`**

App message sending failed with some reason.

## `enum VPNTunnelError`

Reflects errors that can be thrown by custom tunnel provider from network extension side.

**`case notConfigured = 1`**

VPN SDK is not configured properly.

**`case interfaceChange = 2`**

Network interface was changed during connected state.

**`case tunInterfaceFailure = 3`**

Failed to start packet flow.

**`case systemCalledStop = 4`**

OS called stop.

**`case systemCalledSleep = 5`**

OS called sllep.

**`case badConfiguration = 6`**

Configuration decoding failed.

**`case connectionTimeout = 7`**

Connection timeouted.

**`case connectionCanceled = 8`**

Connection was canceled by user.

**`case hydraInternalError(code: Int, name: String?) = 9`**

SDK has catched custom error from Hydra.

**`case failedToSetNetworkSettings = 10`**

Can't prepare network settings.

**`case delegateRestrictsConnect = 11`**

Can't connect because of invalid configuration.

**`case failedToReconfigure = 12`**

Hydra reconfiguration initiated by user failed.

**`case unknown = 13`**

Unknown error.

**`case authenticationFailure = 14`**

Connection can't continue because of authentication failure.

**`case cryptoFailure = 15`**

Data decoding/encoding failed.

**`case tlsFailure = 16`**

Some TLS operation failed.

**`case dnsFailure = 17`**

DNS related problem (usually resolution failed).

**`case connectionCouldNotBeEstablished = 18`**

Connection process was aborted by some other reason (e.g. routing error, server shutdown).

**`case invalidSession = 19`**

Current session has become invalid.

**`case trafficExceeded = 20`**

VPN connection disrupted because the user is out of traffic. **NOTE:** If on-demand feature is used, VPN will be switched to `bypass` mode until user disconnects VPN connection from the application.

**`case credentialsLoadingFailure(debugDescription: String) = 21`**

Credentials loading failed on the tunnel provider side. `debugDescription` value is provided here for debug reason, it shouldn't be displayed as error message to user.

### `VPNTunnelError.HydraInternalErrorCode`

Some codes for `case hydraInternalError(code: Int, name: String?)`

**`connectionDisrupted = 181`**

VPN connection disrupted by broken network connection.

**`connectionNotEstablished = 182`**

VPN client can't connect to VPN node.

**`tokenInvalid = 186`**

VPN is not established due to application error.

### `enum VPNLogShareHelper`

Provides API for VPN debug logs sharing.

**`static func presentActivity(withGroupID groupID: String, usesSystemExtension: Bool, from viewController: UIViewController)`**

Direct sharing method for iOS. Sharing activity will be presented from passed view controller.

**`static func presentActivity(withGroupID groupID: String, usesSystemExtension: Bool, from sender: NSView)`**

Direct sharing method for macOS. Sharing activity will be presented below passed view.

**`static func allLogFileURLs(withGroupID groupID: String, usesSystemExtension: Bool) -> [URL]`**

Method returns log file URLs without any sharing activity presenting.

## `enum RFC1918Result`

Provides result of RFC1918 detection

**`inRange`**

Indicates that current IP address of interface falls into RFC1918 range.

**`outOfRange`**

Indicates that current IP address of interface out of RFC1918 range.

**`invalid`**

Indicates that SDK unable to get or verify the current network interface ip address.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://pango.gitbook.io/paas/sdk/unified-vpn-sdk-for-apple/api-reference.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
