code: def get_domain_connect_template_sync_url(self, domain, provider_id, service_id, redirect_uri=None, params=None,
                                               state=None, group_ids=None):
          
          # TODO: support for signatures
          # TODO: support for provider_name (for shared templates)
  
          if params is None:
              params = {}
  
          config = self.get_domain_config(domain)
  
          self.check_template_supported(config, provider_id, service_id)
  
          if config.urlSyncUX is None:
              raise InvalidDomainConnectSettingsException("No sync URL in config")
  
          sync_url_format = '{}/v2/domainTemplates/providers/{}/services/{}/' \
                            'apply?domain={}&host={}&{}'
  
          if redirect_uri is not None:
              params["redirect_uri"] = redirect_uri
          if state is not None:
              params["state"] = state
          if group_ids is not None:
              params["groupId"] = ",".join(group_ids)
  
          return sync_url_format.format(config.urlSyncUX, provider_id, service_id, config.domain_root, config.host,
                                        urllib.parse.urlencode(sorted(params.items(), key=lambda val: val[0])))
docs: Makes full Domain Connect discovery of a domain and returns full url to request sync consent.
  
          :param domain: str
          :param provider_id: str
          :param service_id: str
          :param redirect_uri: str
          :param params: dict
          :param state: str
          :param group_ids: list(str)
          :return: (str, str)
              first field is an url which shall be used to redirect the browser to
              second field is an indication of error
          :raises: NoDomainConnectRecordException
              when no _domainconnect record found
          :raises: NoDomainConnectSettingsException
              when settings are not found
          :raises: InvalidDomainConnectSettingsException
              when settings contain missing fields