7

If I go to SharePoint 2013 site, click on Admin -> SharePoint, you will see a list of site collections (the link is https://somename-admin.sharepoint.com/_layouts/15/online/SiteCollections.aspx)

What is the REST endpoint URL to get this list of site collections ?

I was trying _api/search/query?querytext='contentclass:sts_site' or _api/search/query?querytext='contentclass:sts_web', but it doesn't give the whole list...

2
  • However, as I said, "querytext='contentclass:sts_site" doesn't give the whole list of site collections. It returns only those accessible for current user. This is the problem.
    – user33021
    Sep 2, 2014 at 13:07
  • how were you able to solve the problem? the answers to this question don't work for me. I only get a subset of Sites. Interestingly, i don't get some of the Site collections for which I am the owner! Aug 1, 2015 at 10:54

5 Answers 5

11

Unfortunately it doesn't seem possible to achieve using neither REST nor JSOM.

So, the workaround, as you correctly mentioned in the question would be to utilize SharePoint Search REST/JSOM and specify contentclass:sts_site to return sites results.

The following REST example demonstrates that:

function searchSites(webUrl,success, failure) {
    var url = webUrl + "/_api/search/query?querytext='contentclass:sts_site'";
    $.ajax({
        url: url,
        method: "GET",
        headers: { "Accept": "application/json; odata=verbose" },
        success: function (data) {
            success(data.d.query);
        },
        error: function (data) {
            failure(data);
        }
    });
}


//print sites info
searchSites(_spPageContextInfo.webAbsoluteUrl,
  function(query){
      var resultsCount = query.PrimaryQueryResult.RelevantResults.RowCount;
      for(var i = 0; i < resultsCount;i++) {
          var row = query.PrimaryQueryResult.RelevantResults.Table.Rows.results[i];
          var siteUrl = row.Cells.results[6].Value;
          console.log(JSON.stringify(siteUrl));
      }   
  },
  function(error){
    console.log(JSON.stringify(error));
  }
);

EDIT:

Note this is using the search query to get the list of site collections. as such, newly added site collections will not appear until the search index is recrawled.

Also this is very unfortunate that this requires being an administrator to do this. I created a new feature request Sharepoint user voice idea for not requiring admin rights to list site collections to handle this.

6
  • This doesn't work for me. I am using Client Credentials Flow to get access token. Is that the issue? URL i hit >>> https://{tenantName}-admin.sharepoint.com/_api/search/query?querytext='.... Jul 24, 2015 at 5:14
  • How will this work for Anonymous access? (APP only auth token) Jul 31, 2015 at 7:06
  • @Vadim doesn't work for me either. This just returns a bunch of stuff values, but it does not have the 2 site collections i created in the admin UI. Is there literally no way to list site collections in the entire API? that's really unfortunate May 3, 2018 at 5:29
  • 1
    To anyone not seeing newly created site collections from this query, it's because the search index hasn't added the site collections yet! you need to either wait or trigger the indexing before this will work! May 4, 2018 at 13:54
  • Another problem is many sharepoint on-prem installations don't have the search service enabled: The search request was unable to connect to the Search Service. Aug 1, 2018 at 17:40
2

There are no REST endpoints at the farm level in SharePoint, so there is no REST endpoint for all the site collections in your farm/tenancy.

You could get all the subwebs for a specific site (/_api/web?$select=Webs&$expand=Webs), but not all the sites in a tenant/farm.

2

For SharePoint on-prem

If the search API is enabled for you, use this answer above: https://sharepoint.stackexchange.com/a/113625/60157

Otherwise...

Soap call - sites.asmx - GetContent

One sure-fire way to get the site collections on your system with REST calls is to make call Soap with your REST client.

You have to make 2+ soap calls to get the result.

C# Code Example:

    public XmlDocument getContent(string siteUrl, String contentType, string contentId) {
      List<string> allSites = new List<string>();
      var _url = string.Format("{0}/_vti_bin/SiteData.asmx", siteUrl);
      var _action = "http://schemas.microsoft.com/sharepoint/soap/GetContent";

      XmlDocument soapEnvelopeXml = CreateSoapEnvelope(contentType, contentId);
      HttpWebRequest webRequest = CreateWebRequest(_url, _action);
      InsertSoapEnvelopeIntoWebRequest(soapEnvelopeXml, webRequest);

      // begin async call to web request.
      IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);

      // suspend this thread until call is complete. You might want to
      // do something usefull here like update your UI.
      asyncResult.AsyncWaitHandle.WaitOne();

      // get the response from the completed web request.
      XmlDocument contentDatabaseResult = new XmlDocument();
      using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult)) {
        using (StreamReader rd = new StreamReader(webResponse.GetResponseStream())) {
          contentDatabaseResult.Load(rd);
        }
      }
      return contentDatabaseResult;
    }

    public List<string> GetAllSiteCollections() {
      List<String> allSites = new List<string>();
      XmlDocument virtualServerGetContentResult = getContent(rootSite, "VirtualServer", null);
      XmlNode contentResultNode = virtualServerGetContentResult.SelectSingleNode("//*[local-name() = 'GetContentResult']");
      if (contentResultNode == null || contentResultNode.InnerText == null) {
        throw new Exception(string.Format("Cannot list top level sites from {0}", rootSite));
      }
      XmlDocument innerXmlDoc = new XmlDocument();
      innerXmlDoc.LoadXml(contentResultNode.InnerText);
      string contentDatabaseId = innerXmlDoc.SelectSingleNode("//*[local-name() = 'ContentDatabase']").Attributes["ID"].Value;
      if (contentDatabaseId == null) {
        throw new Exception(string.Format("Cannot list top level sites from {0}", rootSite));
      }
      XmlDocument contentDatabaseGetContentResult = getContent(rootSite, "ContentDatabase", contentDatabaseId);
      XmlNode contentDatabaseResultNode = contentDatabaseGetContentResult.SelectSingleNode("//*[local-name() = 'GetContentResult']");
      if (contentDatabaseResultNode == null || contentDatabaseResultNode.InnerText == null) {
        throw new Exception(string.Format("Cannot list top level sites from {0}", rootSite));
      }
      innerXmlDoc = new XmlDocument();
      innerXmlDoc.LoadXml(contentDatabaseResultNode.InnerText);
      XmlNodeList sites = innerXmlDoc.SelectNodes("//*[local-name() = 'Site']");
      foreach (XmlNode siteNode in sites) {
        allSites.Add(siteNode.Attributes["URL"].Value);
      }
      return allSites;
    }

    HttpWebRequest CreateWebRequest(string url, string action) {
      HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
      webRequest.Headers.Add("SOAPAction", action);
      webRequest.ContentType = "text/xml;charset=\"utf-8\"";
      webRequest.Accept = "text/xml";
      webRequest.Method = "POST";
      webRequest.Credentials = credentialCache;
      return webRequest;
    }

    XmlDocument CreateSoapEnvelope(string objectType, string objectId) {
      XmlDocument soapEnvelopeDocument = new XmlDocument();
      string soapEnv = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:soap=""http://schemas.microsoft.com/sharepoint/soap/"">
   <soapenv:Header/>
   <soapenv:Body>
      <soap:GetContent>
         <soap:objectType>{0}</soap:objectType>
{1}
         <soap:retrieveChildItems>true</soap:retrieveChildItems>
         <soap:securityOnly>false</soap:securityOnly>
      </soap:GetContent>
   </soapenv:Body>
</soapenv:Envelope>";
      soapEnvelopeDocument.LoadXml(string.Format(soapEnv, objectType,
                                                 objectId == null ? "" : "<soap:objectId>" + objectId + "</soap:objectId>"));
      return soapEnvelopeDocument;
    }

    void InsertSoapEnvelopeIntoWebRequest(XmlDocument soapEnvelopeXml, HttpWebRequest webRequest) {
      using (Stream stream = webRequest.GetRequestStream()) {
        soapEnvelopeXml.Save(stream);
      }
    }
  }

For SharePoint Online

Rest call - WCF ProcessQuery

First see https://pholpar.wordpress.com/2011/05/25/interpreting-network-traffic-generated-by-the-sharepoint-client-object-model/ for how to make rest calls to the WCF client.svc endpoint. I will not include the process of creating SPOIDCRL cookie and getting the X-Digest value. But you will need these.

curl -X POST \
  https://xxxxxxxxx-admin.sharepoint.com/_vti_bin/client.svc/ProcessQuery \
  -H 'Content-Type: text/xml' \
  -H 'Cookie: SPOIDCRL=77u/PD94b.....TwvU1A+' \
  -H 'X-ClientService-ClientTag: TAPS (16.0.7813.0)' \
  -H 'X-FORMS_BASED_AUTH_ACCEPTED: f' \
  -H 'X-RequestDigest: 0x089E7....905ED2601,03 Aug 2018 05:12:10 -0000' \
  -H 'X-RequestForceAuthentication: true' \
  -d '<?xml version="1.0" encoding="UTF-8"?>
<Request xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009" AddExpandoFieldTypeSuffix="true" SchemaVersion="15.0.0.0" LibraryVersion="16.0.7918.1217" ApplicationName="Lucidworks Fusion">
   <Actions>
      <ObjectPath Id="4" ObjectPathId="3" />
      <ObjectPath Id="6" ObjectPathId="5" />
      <Query Id="7" ObjectPathId="5">
         <Query SelectAllProperties="true">
            <Properties>
               <Property Name="NextStartIndexFromSharePoint" ScalarProperty="true" />
            </Properties>
         </Query>
         <ChildItemQuery SelectAllProperties="true">
            <Properties />
         </ChildItemQuery>
      </Query>
   </Actions>
   <ObjectPaths>
      <Constructor Id="3" TypeId="{268004ae-ef6b-4e9b-8425-127220d84719}" />
      <Method Id="5" ParentId="3" Name="GetSitePropertiesFromSharePoint">
         <Parameters>
            <Parameter Type="Null" />
            <Parameter Type="Boolean">false</Parameter>
         </Parameters>
      </Method>
   </ObjectPaths>
</Request>'

The result will contain your site collections.

If you happen to have 1000's site collections in your SharePoint online, you may need to figure out how to change this query to support paging.

1

The query that you have used will only return the sites that the user running the code has access to. Looks like you are trying to get the site collections list from O365 tenant. Here is something that you can try using CSOM.

2
  • 2
    If there is a way to do it not using C# ? I wanted to make a Java application running on a local client machine (not web server) that will be able to get list of site collections.
    – Alex
    Aug 29, 2014 at 14:14
  • 2
    How do I do that through REST API? Is there a way? Aug 1, 2015 at 8:23
1

I know this is an old post but I compare current address to ('https://yourURL/_api/Web/FirstUniqueAncestorSecurableObject').d.Url. If they are equal, I assume I'm talking to the site collection. Please correct me if that is off base but I hope this may help someone in the future.

1
  • Yes this is off base. the question was how do you obtain a list of site collections in the entire sharepoint tenant. not "is this site a site collection" May 3, 2018 at 5:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.