---
title: Forms Service API
slug: cms-12/docs/using-forms-serviceapi
docTags: 
createdAt: 2026-08-10T15:55:53.000Z
---

:::hint{type="info"}
**Note**
[Optimizely Forms](docId:3SbSlJZIS_3iFmghfQA3J) is only supported by MVC-based websites and HTML5-compliant browsers.
:::

The `Forms.ServiceAPI` has the following attributes:

- Exposes RESTful API for reading data of a form.
  - If you specify `neededLanguage`, only expose data where `SYSTEMCOLUMN-language="neededLanguage";` you do not need to show the `SYSTEMCOLUMN-language` column.
  - If you do not specify `neededLanguage`, show data for all languages, and also show `SYSTEMCOLUMN-language`.
- Supports CSV, XML, XLSX, and JSON formats.
- Supports pagination.
- Compatible with OData.
  \- [$filter](https://www.odata.org/documentation/odata-version-2-0/uri-conventions/) defined by OData can be used to filter on `SYSTEMCOLUMN\_SubmitUser and SYSTEMCOLUMN\_FinalizedSubmission`. For example: `http://localhost:56908/EPiServer.Forms.ServiceApi/GetFormData(Id=114,Language=null)?$filter=SYSTEMCOLUMN_SubmitUser`.
  The `SYSTEMCOLUMN\_SubmitTime` is not compatible with OData serializing. You should use `$filter` without `SYSTEMCOLUMN\_SubmitTime` and filter the data by code.
- For implementation, writes the extension on top of the ServiceAPI to use its OAuth2 handling.

:::hint{type="info"}
**Note**
If you enable **Allow Exposing Data Feeds** in a form container, allowed credentials can fetch data with the ServiceAPI.
:::

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/nmJKOWGWU9jba8jX7vN-Q_d154d47-serviceapi-1.png)

## Work with the API

`EPiServer.Forms.ServiceApi` is based on `EPiServer.ServiceApi`.

1. Install the `EPiServer.Forms.ServiceApi` NuGet package with Visual Studio and rebuild the solution.
2. Update the `EPiServer.ServiceApi` to latest version by running the following command in the Package Manager Console.

```csharp
update-package EPiServer.ServiceApi
```

3. Update `appsetting.json` to config `ClientId` and `ClientSecret`

```csharp
"EPiServer": {
        "ServiceApi": {
            "RequireSsl": true,
            "ClientId": "cli",
            "ClientSecret": "cli"
        }
    },
```

4. Bind HTTPS for your site.
   `EPiServer.Forms.ServiceApi` depends on `EPiServer.ServiceApi`, which requires using https for consuming APIs, so you need go to IIS and bind https for your website.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/HrhSQ8dgx4a1fsxq3frvt_91b961a-serviceapi-2.png)

5. Verify that `EPiServer.Forms.ServiceApi` is working.
   Before you can use the `ServiceApi`, access `https://YourSite//EPiServer.Forms.ServiceApi` from a browser. If it returns JSON like this:

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/ILZLHJtb7tIgbhkIOgSl_-20260722-170226.png "serviceapi-2.PNG")

...then it is working. If it does not return anything, re-install nuget then try again

6. Grant permission for the Config user to use `ServiceApi`.
   1. Go to the admin view > **Config**> **Security**> **Permissions for Functions**.
   2. Add the user or group to the **EPiServerServiceApi Read Access** right. This user is for authenticating when you consume the `ServiceApi`.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/bspTrKaZlovmR5ozMuOUe_0289dc7-serviceapi-3.PNG)

7. Implement OAuth2 client to access the service.

```csharp
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;

namespace EPiServer.Forms.ServiceApi.WebTest {
  public class OAuth2Client {
    private string _baseUrl, _username, _password, _accessTokenUri;

    public OAuth2Client(string baseUrl, string username, string password, string accessTokenUri) {
      _baseUrl = baseUrl;
      _username = username;
      _password = password;
      _accessTokenUri = accessTokenUri;
    }

    public string GetData(string uri, string accessToken) {
      using(var client = new HttpClient()) {
        client.BaseAddress = new Uri(_baseUrl);
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

        var response = client.GetAsync(uri).Result;
        if (response.StatusCode == HttpStatusCode.OK) {
          var content = response.Content.ReadAsStringAsync().Result;
          return content;
        }
      }

      return string.Empty;
    }

    public string DeleteData(string uri, string accessToken, int formsId, IEnumerable<string> recordIds) {
      using(var client = new HttpClient()) {
        client.BaseAddress = new Uri(_baseUrl);
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

        var content = JsonConvert.SerializeObject(new {
          Id = formsId,
            SubmissionIds = recordIds
        });

        var postContent = new StringContent(content, Encoding.UTF8, "application/json");
        var response = client.PostAsync(uri, postContent).Result;
        return response.StatusCode.ToString();
      }
    }

    public string GetAccessToken() {
      var token = string.Empty;
      using(var client = new HttpClient()) {
        client.BaseAddress = new Uri(_baseUrl);
        var fields = new Dictionary<string, string> {
            {
              "grant_type",
              "client_credentials"
            },
            {
              "client_id",
              _username
            },
            {
              "client_secret",
              _password
            },
            {
              "scope",
              "epi_service_api"
            }
          };
        var response = client.PostAsync(_accessTokenUri, new FormUrlEncodedContent(fields)).Result;
        if (response.StatusCode == HttpStatusCode.OK) {
          var content = response.Content.ReadAsStringAsync().Result;
          token = (string) JObject.Parse(content).GetValue("access_token");
        }
      }
      return token;
    }
  }
}
```

You can use the OAuth2Client class to access the service to get data. The service exposes the following methods:

- `GetFormsInfo` – Gets forms in the system. Accept language as a parameter; if the language parameter is null, it returns form information in the master language. The requesting user must have read access to the form to get data.
- `GetFormData` – Fetches posted data of a specified form. You need to specify form id and language as parameters; language can be null, which returns data from all languages.
- `GetFieldMapping` – Gets mappings between field name and their friendly name. You need to specify form ID and form language.
- `DeleteFormData` –  in Forms Service API 3.1.0] Del Deletes posted specified form data. You need to specify form Id and SubmissionIds as parameters.

To invoke `DeleteFormData` action, use a POST request and JSON data format for the parameters in the request body. Example:

The service is compatible with OData 8.0. The following example shows how to use these methods.

```csharp
private const string AccessTokenURI = "/api/episerver/connect/token";
private const string FormDataURI = "/EPiServer.Forms.ServiceApi/GetFormData(Id={0},Language=null)?$top=10";
private const string FormMappingURI = "/EPiServer.Forms.ServiceApi/GetFieldMapping(Id={0},Language=null)";
private const string FormsInfoURI = "/EPiServer.Forms.ServiceApi/GetFormsInfo(Language=null)";
private const string FormsDeleteURI = "/EPiServer.Forms.ServiceApi/DeleteFormData";
private static readonly string Username = ConfigurationManager.AppSettings["username"]; // clientId added to access ServiceApi on step 3
private static readonly string Password = ConfigurationManager.AppSettings["password"]; // clientSecret added to access ServiceApi on step 3
private static readonly string SiteUrl = ConfigurationManager.AppSettings["siteUrl"]; // ex: https://vnwks30:17005/

………………………………………………………………………………………………………………………………….
protected void FetchData_Click(object sender, EventArgs e) {
  if (string.IsNullOrEmpty(FormId.Text)) {
    return;
  }

  // for request to https site
  System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate {
    return true;
  };
  var oAuthClient = new OAuth2Client(SiteUrl, Username, Password, AccessTokenURI);
  var accessToken = oAuthClient.GetAccessToken();
  var formsInfo = oAuthClient.GetData(FormsInfoURI, accessToken);
  var mappings = oAuthClient.GetData(string.Format(FormMappingURI, FormId.Text), accessToken);
  var data = oAuthClient.GetData(string.Format(FormDataURI, FormId.Text), accessToken);

  // get the first record return from above function and delete it
  if (data != null) {
    var dataObj = JObject.Parse(data);
    var firstId = dataObj["value"].First["Id"];
    var recordIds = new List<string> {
      firstId.ToString()
    };
    var deleteFirstRecord = oAuthClient.DeleteData(FormsDeleteURI, accessToken, int.Parse(FormId.Text), recordIds);
  }

  // delete all records
  //var dataObj = JObject.Parse(data);
  //var recordIds = new List<string>();
  //foreach (var obj in dataObj["value"])
  //{
  //    recordIds.Add(obj["Id"].ToString());
  //}
  //var deleteAllRecord = oAuthClient.DeleteData(FormsDeleteURI, accessToken, int.Parse(FormId.Text), recordIds);
}
```
