diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java
index cdec9e7a79084dc8919267bdc71612e002ecaf02..b826d338a0ee2a6589e5371bc07a46dd6d0c07b4 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java
@@ -545,11 +545,17 @@ public final class Provider implements Parcelable {
     }
 
     public boolean hasGatewaysInDifferentLocations() {
-        try {
-            return getEipServiceJson().getJSONObject(LOCATIONS).length() > 1;
-        } catch (NullPointerException | JSONException e) {
-            return false;
+        if (apiVersion >= 5) {
+            //FIXME: getService().getLocations()
+            return true;
+        } else {
+            try {
+                return getEipServiceJson().getJSONObject(LOCATIONS).length() > 1;
+            } catch (NullPointerException | JSONException e) {
+                return false;
+            }
         }
+
     }
 
     @Override
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Transport.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Transport.java
index c2590012ea743c1f579fb33eeb27df892b360339..abd42812d1b7f8ea10a9a5b5983e398a85a12588 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/models/Transport.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Transport.java
@@ -1,5 +1,14 @@
 package se.leap.bitmaskclient.base.models;
 
+import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN;
+import static se.leap.bitmaskclient.base.models.Constants.CAPABILITIES;
+import static se.leap.bitmaskclient.base.models.Constants.CERT;
+import static se.leap.bitmaskclient.base.models.Constants.IAT_MODE;
+import static se.leap.bitmaskclient.base.models.Constants.PORTS;
+import static se.leap.bitmaskclient.base.models.Constants.PROTOCOLS;
+import static se.leap.bitmaskclient.base.models.Constants.TRANSPORT;
+
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.google.gson.FieldNamingPolicy;
@@ -7,11 +16,16 @@ import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import com.google.gson.annotations.SerializedName;
 
+import org.json.JSONArray;
 import org.json.JSONObject;
 
 import java.io.Serializable;
+import java.util.Map;
+import java.util.Vector;
 
 import de.blinkt.openvpn.core.connection.Connection;
+import io.swagger.client.model.ModelsBridge;
+import io.swagger.client.model.ModelsGateway;
 
 public class Transport implements Serializable {
     private final String type;
@@ -32,6 +46,13 @@ public class Transport implements Serializable {
         this.options = options;
     }
 
+    public Transport(String type, String[] protocols, @Nullable String[] ports) {
+        this.type = type;
+        this.protocols = protocols;
+        this.ports = ports;
+        this.options = null;
+    }
+
     public String getType() {
         return type;
     }
@@ -67,6 +88,78 @@ public class Transport implements Serializable {
                 fromJson(json.toString(), Transport.class);
     }
 
+    public static Transport createTransportFrom(ModelsBridge modelsBridge) {
+        if (modelsBridge == null) {
+            return null;
+        }
+        Map<String, Object> options = modelsBridge.getOptions();
+        Transport.Options transportOptions = new Transport.Options((String) options.get(CERT), (String) options.get(IAT_MODE));
+        Transport transport = new Transport(
+                modelsBridge.getType(),
+                new String[]{modelsBridge.getTransport()},
+                new String[]{String.valueOf(modelsBridge.getPort())},
+                transportOptions
+        );
+        return transport;
+    }
+
+    public static Transport createTransportFrom(ModelsGateway modelsGateway) {
+        if (modelsGateway == null) {
+            return null;
+        }
+        Transport transport = new Transport(
+                modelsGateway.getType(),
+                new String[]{modelsGateway.getTransport()},
+                new String[]{String.valueOf(modelsGateway.getPort())}
+        );
+        return transport;
+    }
+
+
+    @NonNull
+    public static Vector<Transport> createTransportsFrom(JSONObject gateway, int apiVersion) throws IllegalArgumentException {
+        Vector<Transport> transports = new Vector<>();
+        try {
+            if (apiVersion >= 3) {
+                JSONArray supportedTransports = gateway.getJSONObject(CAPABILITIES).getJSONArray(TRANSPORT);
+                for (int i = 0; i < supportedTransports.length(); i++) {
+                    Transport transport = Transport.fromJson(supportedTransports.getJSONObject(i));
+                    transports.add(transport);
+                }
+            } else {
+                JSONObject capabilities =  gateway.getJSONObject(CAPABILITIES);
+                JSONArray ports = capabilities.getJSONArray(PORTS);
+                JSONArray protocols = capabilities.getJSONArray(PROTOCOLS);
+                String[] portArray = new String[ports.length()];
+                String[] protocolArray = new String[protocols.length()];
+                for (int i = 0; i < ports.length(); i++) {
+                    portArray[i] = String.valueOf(ports.get(i));
+                }
+                for (int i = 0; i < protocols.length(); i++) {
+                    protocolArray[i] = protocols.optString(i);
+                }
+                Transport transport = new Transport(OPENVPN.toString(), protocolArray, portArray);
+                transports.add(transport);
+            }
+        } catch (Exception e) {
+            throw new IllegalArgumentException();
+            //throw new ConfigParser.ConfigParseError("Api version ("+ apiVersion +") did not match required JSON fields");
+        }
+        return transports;
+    }
+
+    public static Vector<Transport> createTransportsFrom(ModelsBridge modelsBridge) {
+        Vector<Transport> transports = new Vector<>();
+        transports.add(Transport.createTransportFrom(modelsBridge));
+        return transports;
+    }
+
+    public static Vector<Transport> createTransportsFrom(ModelsGateway modelsGateway) {
+        Vector<Transport> transports = new Vector<>();
+        transports.add(Transport.createTransportFrom(modelsGateway));
+        return transports;
+    }
+
     public static class Options implements Serializable {
         @Nullable
         private final String cert;
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/BitmaskCoreProvider.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/BitmaskCoreProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..a9797142855d00c6257691be87ee33bf981ed31c
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/BitmaskCoreProvider.java
@@ -0,0 +1,2 @@
+package se.leap.bitmaskclient.base.utils;public class BitmaskCoreProvider {
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
index 16c9285516d77d47ee467b61b23dcc27f5e01e6a..234eb9b0b6d34d8cded5d2360e01ac912e9dfae6 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
@@ -20,6 +20,7 @@ import static de.blinkt.openvpn.core.connection.Connection.TransportType.PT;
 import static se.leap.bitmaskclient.base.models.Constants.FULLNESS;
 import static se.leap.bitmaskclient.base.models.Constants.HOST;
 import static se.leap.bitmaskclient.base.models.Constants.IP_ADDRESS;
+import static se.leap.bitmaskclient.base.models.Constants.IP_ADDRESS6;
 import static se.leap.bitmaskclient.base.models.Constants.LOCATION;
 import static se.leap.bitmaskclient.base.models.Constants.LOCATIONS;
 import static se.leap.bitmaskclient.base.models.Constants.NAME;
@@ -27,6 +28,7 @@ import static se.leap.bitmaskclient.base.models.Constants.OPENVPN_CONFIGURATION;
 import static se.leap.bitmaskclient.base.models.Constants.OVERLOAD;
 import static se.leap.bitmaskclient.base.models.Constants.TIMEZONE;
 import static se.leap.bitmaskclient.base.models.Constants.VERSION;
+import static se.leap.bitmaskclient.base.models.Transport.createTransportsFrom;
 import static se.leap.bitmaskclient.base.utils.PreferenceHelper.allowExperimentalTransports;
 import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getExcludedApps;
 import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningCert;
@@ -47,12 +49,18 @@ import org.json.JSONObject;
 
 import java.io.IOException;
 import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
 import java.util.Set;
 import java.util.Vector;
 
 import de.blinkt.openvpn.VpnProfile;
 import de.blinkt.openvpn.core.ConfigParser;
 import de.blinkt.openvpn.core.connection.Connection;
+import io.swagger.client.model.ModelsBridge;
+import io.swagger.client.model.ModelsEIPService;
+import io.swagger.client.model.ModelsGateway;
+import se.leap.bitmaskclient.base.models.Transport;
 import se.leap.bitmaskclient.base.utils.ConfigHelper;
 
 /**
@@ -71,6 +79,8 @@ public class Gateway {
     private JSONObject generalConfiguration;
     private JSONObject secrets;
     private JSONObject gateway;
+    private Vector<ModelsGateway> modelsGateways;
+    private Vector<ModelsBridge> modelsBridges;
     private JSONObject load;
 
     // the location of a gateway is its name
@@ -78,6 +88,10 @@ public class Gateway {
     private int timezone;
     private int apiVersion;
     private Vector<VpnProfile> vpnProfiles;
+    private String remoteIpAddress;
+    private String remoteIpAddressV6;
+    private String host;
+    private String locationName;
 
     /**
      * Build a gateway object from a JSON OpenVPN gateway definition in eip-service.json
@@ -94,32 +108,62 @@ public class Gateway {
         this.gateway = gateway;
         this.secrets = secrets;
         this.load = load;
+        this.apiVersion = eipDefinition.optInt(VERSION);
+        this.remoteIpAddress = gateway.optString(IP_ADDRESS);
+        this.remoteIpAddressV6 = gateway.optString(IP_ADDRESS6);
+        this.host = gateway.optString(HOST);
+        JSONObject location = getLocationInfo(gateway, eipDefinition);
+        this.locationName = location.optString(NAME);
+        this.timezone = location.optInt(TIMEZONE);
+        VpnConfigGenerator.Configuration configuration = getProfileConfig(Transport.createTransportsFrom(gateway, apiVersion));
+        this.generalConfiguration = getGeneralConfiguration(eipDefinition);
+        this.name = configuration.profileName;
+        this.vpnProfiles = createVPNProfiles(configuration);
+    }
+
+
+    public Gateway(ModelsEIPService eipService, JSONObject secrets, ModelsGateway modelsGateway, int apiVersion) throws ConfigParser.ConfigParseError, JSONException, IOException {
+        this.apiVersion = apiVersion;
+        generalConfiguration = getGeneralConfiguration(eipService);
+        this.secrets = secrets;
+        this.modelsGateways = new Vector<>();
+        this.modelsBridges = new Vector<>();
+        this.modelsGateways.add(modelsGateway);
+
+        this.remoteIpAddress = modelsGateway.getIpAddr();
+        this.remoteIpAddressV6 = modelsGateway.getIp6Addr();
+        this.host = modelsGateway.getHost();
+        this.locationName = "UNKNOWN due to bug in menshen";
+                // TODO eipService.getLocations().get
+        this.timezone = 2; // modelsGateway.getLocation()...
+        this.apiVersion = apiVersion;
+        VpnConfigGenerator.Configuration configuration = getProfileConfig(createTransportsFrom(modelsGateway));
+        this.name = configuration.profileName;
+        this.vpnProfiles = createVPNProfiles(configuration);
+    }
 
-        apiVersion = getApiVersion(eipDefinition);
-        VpnConfigGenerator.Configuration configuration = getProfileConfig(eipDefinition, apiVersion);
-        generalConfiguration = getGeneralConfiguration(eipDefinition);
-        timezone = getTimezone(eipDefinition);
+    public Gateway(ModelsEIPService eipService, JSONObject secrets, ModelsBridge modelsBridge, int apiVersion) throws ConfigParser.ConfigParseError, JSONException, IOException {
+        this.apiVersion = apiVersion;
+        generalConfiguration = getGeneralConfiguration(eipService);
+        this.secrets = secrets;
+        this.modelsGateways = new Vector<>();
+        this.modelsBridges = new Vector<>();
+        this.modelsBridges.add(modelsBridge);
+        remoteIpAddress = modelsBridge.getIpAddr();
+        host = modelsBridge.getHost();
+        locationName = "UNKNOWN due to bug in menshen";
+        // FIXME eipService.getLocations().get
+        timezone = 2; // modelsGateway.getLocation()...
+        this.apiVersion = apiVersion;
+        VpnConfigGenerator.Configuration configuration = getProfileConfig(Transport.createTransportsFrom(modelsBridge));
         name = configuration.profileName;
         vpnProfiles = createVPNProfiles(configuration);
     }
 
-    private VpnConfigGenerator.Configuration getProfileConfig(JSONObject eipDefinition, int apiVersion) {
-        VpnConfigGenerator.Configuration config = new VpnConfigGenerator.Configuration();
-        config.apiVersion = apiVersion;
-        config.preferUDP = getPreferUDP();
-        config.experimentalTransports = allowExperimentalTransports();
-        config.excludedApps = getExcludedApps();
-
-        config.remoteGatewayIP = config.useObfuscationPinning ? getObfuscationPinningIP() : gateway.optString(IP_ADDRESS);
-        config.useObfuscationPinning = useObfuscationPinning();
-        config.profileName = config.useObfuscationPinning ? getObfuscationPinningGatewayLocation() : locationAsName(eipDefinition);
-        if (config.useObfuscationPinning) {
-            config.obfuscationProxyIP = getObfuscationPinningIP();
-            config.obfuscationProxyPort = getObfuscationPinningPort();
-            config.obfuscationProxyCert = getObfuscationPinningCert();
-            config.obfuscationProxyKCP = getObfuscationPinningKCP();
-        }
-        return config;
+
+
+    private VpnConfigGenerator.Configuration getProfileConfig(Vector<Transport> transports) {
+        return VpnConfigGenerator.Configuration.createProfileConfig(transports, apiVersion, remoteIpAddress, remoteIpAddressV6, locationName);
     }
 
     public void updateLoad(JSONObject load) {
@@ -134,29 +178,33 @@ public class Gateway {
         }
     }
 
-    private int getTimezone(JSONObject eipDefinition) {
-        JSONObject location = getLocationInfo(eipDefinition);
-        return location.optInt(TIMEZONE);
-    }
+    private JSONObject getGeneralConfiguration(ModelsEIPService eipService) {
+        JSONObject config = new JSONObject();
+        Map<String, Object> openvpnOptions =  eipService.getOpenvpnConfiguration();
+        Set<String> keys = openvpnOptions.keySet();
+        Iterator<String> i = keys.iterator();
+        while (i.hasNext()) {
+            try {
+                String key = i.next();
+                Object o = openvpnOptions.get(key);
+                config.put(key, o);
+            } catch (JSONException e) {
+                e.printStackTrace();
+            }
+        }
 
-    private int getApiVersion(JSONObject eipDefinition) {
-        return eipDefinition.optInt(VERSION);
+        return config;
     }
 
     public String getRemoteIP() {
-        return gateway.optString(IP_ADDRESS);
+        return remoteIpAddress;
     }
 
     public String getHost() {
-        return gateway.optString(HOST);
+        return host;
     }
 
-    private String locationAsName(JSONObject eipDefinition) {
-        JSONObject location = getLocationInfo(eipDefinition);
-        return location.optString(NAME);
-    }
-
-    private JSONObject getLocationInfo(JSONObject eipDefinition) {
+    private JSONObject getLocationInfo(JSONObject gateway, JSONObject eipDefinition) {
         try {
             JSONObject locations = eipDefinition.getJSONObject(LOCATIONS);
 
@@ -191,9 +239,8 @@ public class Gateway {
      */
     private @NonNull Vector<VpnProfile> createVPNProfiles(VpnConfigGenerator.Configuration profileConfig)
             throws ConfigParser.ConfigParseError, IOException, JSONException {
-        VpnConfigGenerator vpnConfigurationGenerator = new VpnConfigGenerator(generalConfiguration, secrets, gateway, profileConfig);
-        Vector<VpnProfile> profiles = vpnConfigurationGenerator.generateVpnProfiles();
-        return profiles;
+        VpnConfigGenerator vpnConfigurationGenerator = new VpnConfigGenerator(generalConfiguration, secrets, profileConfig);
+        return vpnConfigurationGenerator.generateVpnProfiles();
     }
 
     public String getName() {
@@ -250,8 +297,8 @@ public class Gateway {
         return getProfile(transportType, obfuscationTransportLayerProtocols) != null;
     }
 
-    public HashSet<Connection.TransportType> getSupportedTransports() {
-        HashSet<Connection.TransportType> transportTypes = new HashSet<>();
+    public Set<Connection.TransportType> getSupportedTransports() {
+        Set<Connection.TransportType> transportTypes = new HashSet<>();
         for (VpnProfile p : vpnProfiles) {
             transportTypes.add(p.getTransportType());
         }
@@ -277,4 +324,16 @@ public class Gateway {
         return new Gson().toJson(this, Gateway.class);
     }
 
+    public Gateway addTransport(Transport transport) {
+        Vector<Transport> transports = new Vector<>();
+        transports.add(transport);
+        VpnConfigGenerator.Configuration profileConfig = getProfileConfig(transports);
+        try {
+            Vector<VpnProfile> profiles = createVPNProfiles(profileConfig);
+            vpnProfiles.addAll(profiles);
+        } catch (ConfigParser.ConfigParseError | IOException | JSONException e) {
+            e.printStackTrace();
+        }
+        return this;
+    }
 }
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
index 37360f81ea9868920145b7327d7a4d44773e79d4..d7f3b42ea7357741ffd86de7237d66e02954b5b2 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
@@ -20,8 +20,10 @@ import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4;
 import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4_HOP;
 import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN;
 import static de.blinkt.openvpn.core.connection.Connection.TransportType.PT;
+import static se.leap.bitmaskclient.base.models.Constants.CERT;
 import static se.leap.bitmaskclient.base.models.Constants.GATEWAYS;
 import static se.leap.bitmaskclient.base.models.Constants.HOST;
+import static se.leap.bitmaskclient.base.models.Constants.IAT_MODE;
 import static se.leap.bitmaskclient.base.models.Constants.KCP;
 import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE;
 import static se.leap.bitmaskclient.base.models.Constants.SORTED_GATEWAYS;
@@ -65,6 +67,9 @@ import de.blinkt.openvpn.core.ConfigParser;
 import de.blinkt.openvpn.core.VpnStatus;
 import de.blinkt.openvpn.core.connection.Connection;
 import de.blinkt.openvpn.core.connection.Connection.TransportType;
+import io.swagger.client.model.ModelsBridge;
+import io.swagger.client.model.ModelsEIPService;
+import io.swagger.client.model.ModelsGateway;
 import se.leap.bitmaskclient.BuildConfig;
 import se.leap.bitmaskclient.R;
 import se.leap.bitmaskclient.base.models.GatewayJson;
@@ -415,84 +420,150 @@ public class GatewaysManager {
         return new Gson().toJson(gateways, listType);
     }
 
-    /**
-     * parse gateways from Provider's eip service
-     * @param provider
-     */
-     private void parseDefaultGateways(Provider provider) {
-         try {
-             JSONObject eipDefinition = provider.getEipServiceJson();
-             JSONObject secrets = secretsConfigurationFromCurrentProvider();
-             JSONArray gatewaysDefined = new JSONArray();
-             try {
-                 gatewaysDefined = eipDefinition.getJSONArray(GATEWAYS);
-             } catch (Exception e) {
-                 e.printStackTrace();
-             }
-
-             if (PreferenceHelper.useObfuscationPinning()) {
-                 try {
-                     Transport[] transports = new Transport[]{
-                             new Transport(OBFS4.toString(),
-                                     new String[]{getObfuscationPinningKCP() ? "kcp" : "tcp"},
-                                     new String[]{getObfuscationPinningPort()},
-                                     getObfuscationPinningCert())};
-                     GatewayJson.Capabilities capabilities = new GatewayJson.Capabilities(false, false, false, transports, false);
-                     GatewayJson gatewayJson = new GatewayJson(context.getString(R.string.unknown_location), getObfuscationPinningIP(
-
-                     ), null, PINNED_OBFUSCATION_PROXY, capabilities);
-                     Gateway gateway = new Gateway(eipDefinition, secrets, new JSONObject(gatewayJson.toString()));
-                     addGateway(gateway);
-                 } catch (JSONException | ConfigParser.ConfigParseError | IOException e) {
-                     e.printStackTrace();
-                 }
-             } else {
-                 for (int i = 0; i < gatewaysDefined.length(); i++) {
-                     try {
-                         JSONObject gw = gatewaysDefined.getJSONObject(i);
-                         Gateway aux = new Gateway(eipDefinition, secrets, gw);
-                         if (gateways.get(aux.getHost()) == null) {
-                             addGateway(aux);
-                         }
-                     } catch (JSONException | IOException e) {
-                         e.printStackTrace();
-                         VpnStatus.logError("Unable to parse gateway config!");
-                     } catch (ConfigParser.ConfigParseError e) {
-                         VpnStatus.logError("Unable to parse gateway config: " + e.getLocalizedMessage());
-                     }
-                 }
-             }
-         } catch (NullPointerException npe) {
-             npe.printStackTrace();
-         }
+    public void parseGatewaysV3(Provider provider) {
+        try {
+            JSONObject eipDefinition = provider.getEipServiceJson();
+            JSONObject secrets = secretsConfigurationFromCurrentProvider();
+            JSONArray gatewaysDefined = new JSONArray();
+            try {
+                gatewaysDefined = eipDefinition.getJSONArray(GATEWAYS);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+            if (PreferenceHelper.useObfuscationPinning()) {
+                try {
+                    Transport[] transports = new Transport[]{
+                            new Transport(OBFS4.toString(),
+                                    new String[]{getObfuscationPinningKCP() ? "kcp" : "tcp"},
+                                    new String[]{getObfuscationPinningPort()},
+                                    getObfuscationPinningCert())};
+                    GatewayJson.Capabilities capabilities = new GatewayJson.Capabilities(false, false, false, transports, false);
+                    GatewayJson gatewayJson = new GatewayJson(context.getString(R.string.unknown_location), getObfuscationPinningIP(
+
+                    ), null, PINNED_OBFUSCATION_PROXY, capabilities);
+                    Gateway gateway = new Gateway(eipDefinition, secrets, new JSONObject(gatewayJson.toString()));
+                    addGateway(gateway);
+                } catch (JSONException | ConfigParser.ConfigParseError | IOException e) {
+                    e.printStackTrace();
+                }
+            } else {
+                for (int i = 0; i < gatewaysDefined.length(); i++) {
+                    try {
+                        JSONObject gw = gatewaysDefined.getJSONObject(i);
+                        Gateway aux = new Gateway(eipDefinition, secrets, gw);
+                        if (gateways.get(aux.getHost()) == null) {
+                            addGateway(aux);
+                        }
+                    } catch (JSONException | IOException e) {
+                        e.printStackTrace();
+                        VpnStatus.logError("Unable to parse gateway config!");
+                    } catch (ConfigParser.ConfigParseError e) {
+                        VpnStatus.logError("Unable to parse gateway config: " + e.getLocalizedMessage());
+                    }
+                }
+            }
+        } catch (NullPointerException npe) {
+            npe.printStackTrace();
+        }
+
+        if (BuildConfig.BUILD_TYPE.equals("debug") && handleGatewayPinning()) {
+            return;
+        }
+
+        // parse v3 menshen geoIP json variants
+        if (hasSortedGatewaysWithLoad(provider)) {
+            parseGatewaysWithLoad(provider);
+        } else {
+            parseSimpleGatewayList(provider);
+        }
+    }
+
+    public void parseGatewaysV5(Provider provider) {
+        ModelsGateway[] modelsGateways = provider.getGateways();
+        ModelsBridge[] modelsBridges = provider.getBridges();
+        ModelsEIPService modelsEIPService = provider.getService();
+        JSONObject secrets = secretsConfigurationFromCurrentProvider();
+        int apiVersion = provider.getApiVersion();
+
+        if (PreferenceHelper.useObfuscationPinning()) {
+            try {
+                ModelsBridge modelsBridge = new ModelsBridge();
+                modelsBridge.ipAddr(getObfuscationPinningIP());
+                modelsBridge.port(Integer.valueOf(getObfuscationPinningPort()));
+                HashMap<String, Object> options = new HashMap<>();
+                options.put(CERT, getObfuscationPinningCert());
+                options.put(IAT_MODE, "0");
+                modelsBridge.options(options);
+                modelsBridge.transport(getObfuscationPinningKCP() ? "kcp" : "tcp");
+                modelsBridge.type(OBFS4.toString());
+                modelsBridge.host(PINNED_OBFUSCATION_PROXY);
+                Gateway gateway = new Gateway(modelsEIPService, secrets, modelsBridge, provider.getApiVersion());
+                addGateway(gateway);
+            } catch (NumberFormatException | ConfigParser.ConfigParseError | JSONException |
+                     IOException e) {
+                e.printStackTrace();
+            }
+        } else {
+            for (ModelsGateway modelsGateway : modelsGateways) {
+                String host = modelsGateway.getHost();
+                Gateway gateway = gateways.get(host);
+                if (gateway == null) {
+                    try {
+                        addGateway(new Gateway(modelsEIPService, secrets, modelsGateway, apiVersion));
+                    } catch (ConfigParser.ConfigParseError | JSONException | IOException e) {
+                        e.printStackTrace();
+                    }
+                } else {
+                    addGateway(gateway.addTransport(Transport.createTransportFrom(modelsGateway)));
+                }
+            }
+            for (ModelsBridge modelsBridge : modelsBridges) {
+                String host = modelsBridge.getHost();
+                Gateway gateway = gateways.get(host);
+                if (gateway == null) {
+                    try {
+                        addGateway(new Gateway(modelsEIPService, secrets, modelsBridge, apiVersion));
+                    } catch (ConfigParser.ConfigParseError | JSONException | IOException e) {
+                        e.printStackTrace();
+                    }
+                } else {
+                    addGateway(gateway.addTransport(Transport.createTransportFrom(modelsBridge)));
+                }
+            }
+        }
+
+        if (BuildConfig.BUILD_TYPE.equals("debug")) {
+            handleGatewayPinning();
+        }
     }
 
     private void parseSimpleGatewayList(Provider provider) {
-         try {
-             JSONObject geoIpJson = provider.getGeoIpJson();
-             JSONArray gatewaylist = geoIpJson.getJSONArray(GATEWAYS);
-
-             for (int i = 0; i < gatewaylist.length(); i++) {
-                 try {
-                     String key = gatewaylist.getString(i);
-                     if (gateways.containsKey(key)) {
-                         presortedList.add(gateways.get(key));
-                     }
-                 } catch (JSONException e) {
-                     e.printStackTrace();
-                 }
-             }
-         } catch (NullPointerException | JSONException npe) {
-             Log.d(TAG, "No valid geoip json found: " + npe.getLocalizedMessage());
-         }
+        try {
+            JSONObject geoIpJson = provider.getGeoIpJson();
+            JSONArray gatewaylist = geoIpJson.getJSONArray(GATEWAYS);
+
+            for (int i = 0; i < gatewaylist.length(); i++) {
+                try {
+                    String key = gatewaylist.getString(i);
+                    if (gateways.containsKey(key)) {
+                        presortedList.add(gateways.get(key));
+                    }
+                } catch (JSONException e) {
+                    e.printStackTrace();
+                }
+            }
+        } catch (NullPointerException | JSONException npe) {
+            Log.d(TAG, "No valid geoip json found: " + npe.getLocalizedMessage());
+        }
     }
 
     private boolean hasSortedGatewaysWithLoad(@Nullable Provider provider) {
-         if (provider == null) {
-             return false;
-         }
-         JSONObject geoIpJson = provider.getGeoIpJson();
-         return geoIpJson.has(SORTED_GATEWAYS);
+        if (provider == null) {
+            return false;
+        }
+        JSONObject geoIpJson = provider.getGeoIpJson();
+        return geoIpJson.has(SORTED_GATEWAYS);
     }
 
     private void parseGatewaysWithLoad(Provider provider) {
@@ -534,30 +605,28 @@ public class GatewaysManager {
     }
 
     private void configureFromCurrentProvider() {
-         Provider provider = ProviderObservable.getInstance().getCurrentProvider();
-         parseDefaultGateways(provider);
-         if (BuildConfig.BUILD_TYPE.equals("debug") && handleGatewayPinning()) {
-             return;
-         }
-         if (hasSortedGatewaysWithLoad(provider)) {
-             parseGatewaysWithLoad(provider);
-         } else {
-             parseSimpleGatewayList(provider);
-         }
-
+        Provider provider = ProviderObservable.getInstance().getCurrentProvider();
+        if (provider == null) {
+            return;
+        }
+        if (provider.getApiVersion() < 5) {
+            parseGatewaysV3(provider);
+        } else {
+            parseGatewaysV5(provider);
+        }
     }
 
     private boolean handleGatewayPinning() {
-         String host = PreferenceHelper.getPinnedGateway();
-         if (host == null) {
-             return false;
-         }
-         Gateway gateway = gateways.get(host);
-         gateways.clear();
-         if (gateway != null) {
-             gateways.put(host, gateway);
-         }
-         return true;
+        String host = PreferenceHelper.getPinnedGateway();
+        if (host == null) {
+            return false;
+        }
+        Gateway gateway = gateways.get(host);
+        gateways.clear();
+        if (gateway != null) {
+            gateways.put(host, gateway);
+        }
+        return true;
     }
 
 }
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
index 5defa7e67d95eac69bb60afabc1d7e2e19847a96..f988dfa0174d63df4fcdf75863ecc9b7f24e69ce 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java
@@ -19,22 +19,25 @@ package se.leap.bitmaskclient.eip;
 import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4;
 import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4_HOP;
 import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN;
-import static se.leap.bitmaskclient.base.models.Constants.CAPABILITIES;
-import static se.leap.bitmaskclient.base.models.Constants.IP_ADDRESS;
-import static se.leap.bitmaskclient.base.models.Constants.IP_ADDRESS6;
 import static se.leap.bitmaskclient.base.models.Constants.KCP;
-import static se.leap.bitmaskclient.base.models.Constants.PORTS;
-import static se.leap.bitmaskclient.base.models.Constants.PROTOCOLS;
 import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE;
 import static se.leap.bitmaskclient.base.models.Constants.REMOTE;
 import static se.leap.bitmaskclient.base.models.Constants.TCP;
-import static se.leap.bitmaskclient.base.models.Constants.TRANSPORT;
 import static se.leap.bitmaskclient.base.models.Constants.UDP;
-
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.allowExperimentalTransports;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getExcludedApps;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningCert;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningGatewayLocation;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningIP;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningKCP;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningPort;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferUDP;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useObfuscationPinning;
+
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
-import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
@@ -57,7 +60,6 @@ import se.leap.bitmaskclient.pluggableTransports.models.Obfs4Options;
 
 public class VpnConfigGenerator {
     private final JSONObject generalConfiguration;
-    private final JSONObject gateway;
     private final JSONObject secrets;
     Vector<Transport> transports = new Vector<>();
     private final int apiVersion;
@@ -69,6 +71,7 @@ public class VpnConfigGenerator {
     private final String obfuscationPinningCert;
     private final boolean obfuscationPinningKCP;
     private final String remoteGatewayIP;
+    private final String remoteGatewayIPv6;
     private final String profileName;
     private final Set<String> excludedApps;
 
@@ -81,6 +84,7 @@ public class VpnConfigGenerator {
         boolean preferUDP;
         boolean experimentalTransports;
         String remoteGatewayIP = "";
+        String remoteGatewayIPv6 = "";
         String profileName = "";
         Set<String> excludedApps = null;
 
@@ -89,11 +93,33 @@ public class VpnConfigGenerator {
         String obfuscationProxyIP = "";
         String obfuscationProxyPort = "";
         String obfuscationProxyCert = "";
+        Vector<Transport> transports = new Vector<>();
+
+        public static VpnConfigGenerator.Configuration createProfileConfig(Vector<Transport> transports, int apiVersion, String remoteIpAddress, String remoteIpAddressV6, String locationName) {
+            VpnConfigGenerator.Configuration config = new VpnConfigGenerator.Configuration();
+            config.apiVersion = apiVersion;
+            config.preferUDP = getPreferUDP();
+            config.experimentalTransports = allowExperimentalTransports();
+            config.excludedApps = getExcludedApps();
+
+            config.remoteGatewayIP = config.useObfuscationPinning ? getObfuscationPinningIP() : remoteIpAddress;
+            config.remoteGatewayIPv6 = config.useObfuscationPinning ? null : remoteIpAddressV6;
+            config.useObfuscationPinning = useObfuscationPinning();
+            config.profileName = config.useObfuscationPinning ? getObfuscationPinningGatewayLocation() : locationName;
+            if (config.useObfuscationPinning) {
+                config.obfuscationProxyIP = getObfuscationPinningIP();
+                config.obfuscationProxyPort = getObfuscationPinningPort();
+                config.obfuscationProxyCert = getObfuscationPinningCert();
+                config.obfuscationProxyKCP = getObfuscationPinningKCP();
+            }
+            config.transports = transports;
+            return config;
+        }
     }
 
-    public VpnConfigGenerator(JSONObject generalConfiguration, JSONObject secrets, JSONObject gateway, Configuration config) throws ConfigParser.ConfigParseError {
+
+    public VpnConfigGenerator(JSONObject generalConfiguration, JSONObject secrets, Configuration config) {
         this.generalConfiguration = generalConfiguration;
-        this.gateway = gateway;
         this.secrets = secrets;
         this.apiVersion = config.apiVersion;
         this.preferUDP = config.preferUDP;
@@ -104,23 +130,10 @@ public class VpnConfigGenerator {
         this.obfuscationPinningCert = config.obfuscationProxyCert;
         this.obfuscationPinningKCP = config.obfuscationProxyKCP;
         this.remoteGatewayIP = config.remoteGatewayIP;
+        this.remoteGatewayIPv6 = config.remoteGatewayIPv6;
+        this.transports = config.transports;
         this.profileName = config.profileName;
         this.excludedApps = config.excludedApps;
-        checkCapabilities();
-    }
-
-    public void checkCapabilities() throws ConfigParser.ConfigParseError {
-        try {
-            if (apiVersion >= 3) {
-                JSONArray supportedTransports = gateway.getJSONObject(CAPABILITIES).getJSONArray(TRANSPORT);
-                for (int i = 0; i < supportedTransports.length(); i++) {
-                    Transport transport = Transport.fromJson(supportedTransports.getJSONObject(i));
-                    transports.add(transport);
-                }
-            }
-        } catch (Exception e) {
-            throw new ConfigParser.ConfigParseError("Api version ("+ apiVersion +") did not match required JSON fields");
-        }
     }
 
     public Vector<VpnProfile> generateVpnProfiles() throws
@@ -128,42 +141,28 @@ public class VpnConfigGenerator {
             NumberFormatException {
         Vector<VpnProfile> profiles = new Vector<>();
 
-        if (apiVersion >= 3) {
-            for (Transport transport : transports){
-                if (transport.getTransportType().isPluggableTransport()) {
-                    Transport.Options transportOptions = transport.getOptions();
-                    if (!experimentalTransports && transportOptions != null && transportOptions.isExperimental()) {
-                        continue;
-                    }
-                } else if (transport.getTransportType() == OPENVPN && useObfuscationPinning) {
+        for (Transport transport : transports){
+            if (transport.getTransportType().isPluggableTransport()) {
+                Transport.Options transportOptions = transport.getOptions();
+                if (!experimentalTransports && transportOptions != null && transportOptions.isExperimental()) {
                     continue;
                 }
-                try {
-                    profiles.add(createProfile(transport));
-                } catch (ConfigParser.ConfigParseError | NumberFormatException | JSONException | IOException e) {
-                    e.printStackTrace();
-                }
+            } else if (transport.getTransportType() == OPENVPN && useObfuscationPinning) {
+                continue;
             }
-        } else if (supportsOpenvpn()) {
-            // API v1 - TODO: let's remove support for API v1 soon
             try {
-                profiles.add(createApiv1OpenvpnProfile());
+                profiles.add(createProfile(transport));
             } catch (ConfigParser.ConfigParseError | NumberFormatException | JSONException | IOException e) {
                 e.printStackTrace();
             }
         }
+
         if (profiles.isEmpty()) {
             throw new ConfigParser.ConfigParseError("No supported transports detected.");
         }
         return profiles;
     }
 
-    private boolean supportsOpenvpn() {
-        return !useObfuscationPinning &&
-                ((apiVersion >= 3 && getTransport(OPENVPN) != null) ||
-                        (apiVersion < 3 && !gatewayConfiguration(null).isEmpty()));
-    }
-
     private String getConfigurationString(Transport transport) {
         return generalConfiguration()
                 + newLine
@@ -193,23 +192,8 @@ public class VpnConfigGenerator {
         return profile;
     }
 
-    @VisibleForTesting
-    protected VpnProfile createApiv1OpenvpnProfile() throws IOException, ConfigParser.ConfigParseError, JSONException {
-        String configuration = getConfigurationString(null);
-        ConfigParser icsOpenvpnConfigParser = new ConfigParser();
-        icsOpenvpnConfigParser.parseConfig(new StringReader(configuration));
-
-        VpnProfile profile = icsOpenvpnConfigParser.convertProfile(OPENVPN);
-        profile.mName = profileName;
-        profile.mGatewayIp = remoteGatewayIP;
-        if (excludedApps != null) {
-            profile.mAllowedAppsVpn = new HashSet<>(excludedApps);
-        }
-        return profile;
-    }
-
-    private Obfs4Options getObfs4Options(Transport transport) throws JSONException {
-        String ip = gateway.getString(IP_ADDRESS);
+    private Obfs4Options getObfs4Options(Transport transport) throws JSONException, NullPointerException {
+        String ip = remoteGatewayIP;
         if (useObfuscationPinning) {
             transport = new Transport(OBFS4.toString(),
                     new String[]{obfuscationPinningKCP ? KCP : TCP},
@@ -223,9 +207,9 @@ public class VpnConfigGenerator {
     private String generalConfiguration() {
         String commonOptions = "";
         try {
-            Iterator keys = generalConfiguration.keys();
+            Iterator<String> keys = generalConfiguration.keys();
             while (keys.hasNext()) {
-                String key = keys.next().toString();
+                String key = keys.next();
 
                 commonOptions += key + " ";
                 for (String word : String.valueOf(generalConfiguration.get(key)).split(" "))
@@ -243,32 +227,19 @@ public class VpnConfigGenerator {
         return commonOptions;
     }
 
-    private String gatewayConfiguration(@Nullable Transport transport) {
+    private String gatewayConfiguration(@NonNull Transport transport) {
         String configs = "";
 
         StringBuilder stringBuilder = new StringBuilder();
         try {
-            String ipAddress = null;
-            JSONObject capabilities = gateway.getJSONObject(CAPABILITIES);
             switch (apiVersion) {
-                default:
-                case 1:
-                case 2:
-                    ipAddress = gateway.getString(IP_ADDRESS);
-                    gatewayConfigApiv1(stringBuilder, ipAddress, capabilities);
-                    break;
-                case 3:
-                case 4:
-                    ipAddress = gateway.optString(IP_ADDRESS);
-                    String ipAddress6 = gateway.optString(IP_ADDRESS6);
-                    String[] ipAddresses = ipAddress6.isEmpty()  ?
-                            new String[]{ipAddress} :
-                            new String[]{ipAddress6, ipAddress};
-                    if (transport == null) {
-                        throw new NullPointerException("Transport is not allowed to be null in APIv3+");
-                    }
+                case 1, 2 -> gatewayConfigApiv1(transport, stringBuilder, remoteGatewayIP);
+                case 3, 4, 5 -> {
+                    String[] ipAddresses = (remoteGatewayIPv6 == null || remoteGatewayIPv6.isEmpty()) ?
+                            new String[]{remoteGatewayIP} :
+                            new String[]{remoteGatewayIPv6, remoteGatewayIP};
                     gatewayConfigMinApiv3(transport, stringBuilder, ipAddresses);
-                    break;
+                }
             }
         } catch (JSONException | NullPointerException e) {
             // TODO Auto-generated catch block
@@ -300,15 +271,15 @@ public class VpnConfigGenerator {
         return null;
     }
 
-    private void gatewayConfigApiv1(StringBuilder stringBuilder, String ipAddress, JSONObject capabilities) throws JSONException {
-        int port;
-        String protocol;
-        JSONArray ports = capabilities.getJSONArray(PORTS);
-        JSONArray protocols = capabilities.getJSONArray(PROTOCOLS);
-        for (int i = 0; i < ports.length(); i++) {
-            port = ports.getInt(i);
-            for (int j = 0; j < protocols.length(); j++) {
-                protocol = protocols.optString(j);
+    private void gatewayConfigApiv1(Transport transport, StringBuilder stringBuilder, String ipAddress) throws JSONException {
+        if (transport == null || transport.getProtocols() == null || transport.getPorts() == null) {
+            VpnStatus.logError("Misconfigured provider: missing details for transport openvpn on gateway " + ipAddress);
+            return;
+        }
+        String[] ports = transport.getPorts();
+        String[] protocols = transport.getProtocols();
+        for (String port : ports) {
+            for (String protocol : protocols) {
                 String newRemote = REMOTE + " " + ipAddress + " " + port + " " + protocol + newLine;
                 stringBuilder.append(newRemote);
             }