---
title: Discover the platform
slug: cms-12/api/discovering-the-platform
docTags: 
createdAt: 2026-08-07T16:45:44.000Z
---

## Services

The primary interaction point with the Optimizely Community API is through service classes, each implementing an interface following the naming convention `I{Feature-Name}Service`. Examples include:

- `ICommentService`
- `IRatingService`
- `IGroupService`

For Optimizely Content Management System (CMS) sites with the feature's site integration package installed, you can get an instance of a service from the inversion of control (IoC) container.

Example

```csharp
var commentService = EPiServer.ServiceLocation.ServiceLocator.Current.GetInstance<ICommentService>();
```

For non-Optimizely CMS sites, you can get an instance of a service from the default factory classes provided within the package.

Example

```csharp
var factory = new EPiServer.Social.Moderation.Factories.DefaultWorkflowServiceFactory();
var workflowService = factory.Create();
```

## Data models

Data models consumed and returned by the Community API's services are found under the "core" namespace for each platform feature, following the convention `EPiServer.Social.{Feature-Name}.Core`. For example:

- `EPiServer.Social.Comments.Core`
- `EPiServer.Social.Ratings.Core`

## Exceptions

Exceptions thrown by the Community API's services are located in the `Core` namespace (`EPiServer.Social.{Feature-Name}.Core`) for feature-specific exceptions, and in `EPiServer.Social.Common` for shared platform exceptions.

## Platform exceptions

The Optimizely Community API features share several exception types to communicate general platform error situations.

### SocialAuthenticationException

A `SocialAuthenticationException` is thrown when a request is deemed unauthentic.

This error most commonly occurs when:

- The application's configuration is missing one or more of its authentication settings.
- The application's configuration contains inaccurate authentication settings.
- The application's server time is inaccurate.

For information regarding configuration and authentication, see "Get connected" in Install Optimizely Community.

### MaximumDataSizeExceededException

A `MaximumDataSizeExceededException` is thrown when a request exceeds the platform's size restriction of 10 kilobytes for social content.

This restriction applies to any given social entity, including native properties, optional extension data, and any overhead.

For example, consider a simple comment containing an author, body, and parent reference. Consider that you also composed this comment with custom extension data. The content associated with each of those native comment properties and the extension data contribute to the total size of the request.

The platform does not explicitly restrict the amount of content associated with any individual property of a social content model. This lets you prioritize content size for native content models versus custom extension data.

:::hint{type="info"}
**Note**

Applications should enforce content limits to minimize this exception.
:::

### RateLimitExceededException

A `RateLimitExceededException` is thrown when an application issues too many requests over a short period. All requests are tallied and compared against the rate limit. When an application exceeds the rate limit, the Optimizely Community API stops processing requests until a certain time has elapsed (a "request interval").

The exception provides additional information to help regulate the application's request rate. That information includes:

- `RequestInterval` – The length of time in which requests are tallied.
- `RequestsIssued` – The number of requests already issued in the request interval.
- `RequestLimit` – The maximum number of requests allowed in a given request interval.
- `RetryAfter` – The time remaining until the application may resume issuing requests.

If your application regularly encounters this exception, consider:

- Optimize your code to minimize unnecessary API calls.
- Cache frequently accessed data.
- Actively regulate the application's request rate to ensure the application never encounters the issue.
- Implement logic to pause and retry requests after reaching the limit.

### SocialCommunicationException

A `SocialCommunicationException` is thrown when a request encounters a fundamental communication issue.

This error most commonly occurs when:

- The application cannot connect or communicate with Optimizely Community API cloud services.
- A request from the application exceeds the configured timeout.

### SocialException

A `SocialException` is thrown when a request encounters an unexpected error scenario. The exception contains a message, status code, error code, and additional reasoning to describe the error.

This error most commonly occurs when:

- The application's configuration is missing or malformed.
- The platform encountered an unexpected service error.

## Feature exceptions

Individual services may also throw exceptions unique to the feature they support. Details can be found in the documentation for each API.

## Reference and IDs

The Optimizely Community API identifies data by `Id` and `Reference`, with important semantic distinctions. See also: [Work with Optimizely Community API References](https://world.optimizely.com/blogs/benjamin-schaefer/dates/2017/4/Workin-with-Episerver-Social-References/).

### Ids

`Id` classes are specific to a feature's entities (`{Feature-Name}Id` convention), with internally-generated values used to distinguish individual entities. Examples include:

- `CommentId`
- `GroupId`
- `WorkflowId`

They are accepted by services for retrieving specific data instances.

### Reference

The `Reference` class identifies users or resources *outside* the platform, establishing relationships between social content and external entities.

The developer defines the value within a reference class. It contains the information necessary to identify or classify the resource or user to which social content is related.

The platform provides a `Reference` class that is used to identify any target entity in your application. For example, a resource, like Optimizely CMS content, or a product or a user, like an Optimizely CMS user.

### Best practices for defining references

Ensure your reference scheme is:

- Capable of uniquely identifying entities.
- Interpretable by your application.
- Robust for future enhancements.

Consider factors like: **Platform**, **Provider**, **Classification**, **Categorization**, and **Facets**. A URI or similar namespace scheme is recommended.

Example for ecommerce content:

```csharp
resource://optimizely/commerce/{product-identifier}/{variant-identifier}/{facet-identifier}
```

## Criteria

The Optimizely Community API services allow retrieval of custom result sets using criteria. A `Criteria<TFilter>` class encapsulates specifications for retrieving a collection of results.

### Filter

The `TFilter` type parameter identifies the class encapsulating filter specifications. The `Filter` property accepts an instance of this class to refine a result set.

### PageInfo

The `PageInfo` property accepts an instance of a class defining pagination specifications:

- **Page size**: Maximum number of results (default 10 if not specified, must be >= 0).
- **Page offset**: Zero-based index to start retrieving results (must be >= 0).
- **CalculateTotalCount**: Specifies if a total result count should be calculated. If `true`, the `TotalCount` property on `ResultPage` will be populated; otherwise, it defaults to -1.

### Best practices for paginating results

Large page sizes or deep offsets can negatively impact performance. Balance request size, volume, and user experience. Retrieving `TotalCount` when not needed adversely affects return time.

### OrderBy

The `OrderBy` property accepts a collection of `SortInfo` rules describing how to sort the result set.

`SortInfo` identifies the field and direction for sorting.

A subset of fields on data models is available for sorting, exposed statically on classes named `{Feature-Name}SortFields` (e.g., `CommentSortFields`, `RatingSortFields`).

Sorting rules are processed in order, with subsequent rules acting as fallbacks for matching values.

### Best practices for sorting results

Specify fallback sorting rules if consistency in result ordering is important, especially when navigating multiple pages. Sorting of string values is based on Unicode value; standardize data in code and store as duplicate property on extension data if alternative ordering is required.

## Result sets

Services with bulk retrieval capabilities deliver results in a paginated fashion, represented by a `ResultPage<T>` class.

### Results

The `T` type parameter identifies the model for the returned data (e.g., `Comment`, `Rating`). The `Results` property gets the collection of individual result items.

### TotalCount

The `TotalCount` property provides the total count of items from the query. It is calculated only if `CalculateTotalCount` in `PageInfo` is set to `true`. If `CalculateTotalCount` is `false`, `TotalCount` is -1.

### Info

The `Info` property refers to the paging specifications used when the request was issued.

### HasMore

The `HasMore` property is a boolean indicating if more items exist beyond the current page. This helps determine if an additional query with an incremented `PageOffset` would return more results.

## Composites

The Optimizely Community API supports data extensibility by allowing native entities to be composed with custom data models, known as Composites.

### What is a composite?

A `Composite` represents a pairing of a native platform entity and its associated extension data. Extension data is a .NET class defined within your application to capture additional details.

### Define extension data

Extension data is a .NET class for additional details.

**Considerations:**

- **Queryability**: Design for filtering and sorting by primitive value types within extension data.
- **Maintainability**: Anticipate future enhancements and changes.
- **Performance**: Keep extension data light.

**Constraints for extension data classes:**

- Public, parameter-less constructor.
- No nested data in a polymorphic manner (e.g., child as the `Object` type).
- No self-references or referential loops.
- Class name, assembly names, and namespaces must remain stable.
- Minimize size to avoid exceeding platform size restrictions.

**Additional caveats:**

- `DateTime` values are stored and returned as UTC.
- `DateTime` precision is up to the millisecond.
- `Decimal` type is not supported; stored as `double` and subject to rounding errors.

### Composite criteria

Services supporting Composites provide methods for retrieving them, accepting `CompositeCriteria<TFilter, TExtension>`. This class extends `Criteria`, incorporating its capabilities while adding enhancements.

### ExtensionFilter

The `TExtension` type parameter implicitly filters for composites with extension data of this type. The `ExtensionFilter` property accepts a Boolean expression (represented as a tree structure) to filter by values in your extension data.

### IncludeSubclasses

A boolean indicating whether to include items where `TExtension` appears anywhere in the type hierarchy of their associated extension data (`true` by default), or only explicit `TExtension` types (`false`).

### Filter composites

Filter Expressions are Boolean expressions (tree structures) used to filter `Composites` by values in their extension data. The `FilterExpressionBuilder<TExtension>` class provides methods and operator overloads for constructing these expressions.

Boolean operators can compare fields of `String`, `Boolean`, `Int`, `Long`, `Double`, `DateTime`.

Example of Filter Expression construction:

```csharp
var luckyNumberOf7 = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.LuckyNumber).EqualTo(7);
var bornBefore1990 = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).LessThan(new DateTime(1990, 1, 1));
var combinedExpression = FilterExpressionBuilder<MyCommentExtension>.And(luckyNumberOf7, bornBefore1990);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{
    ExtensionFilter = combinedExpression
};
```

### Best practices for defining filter expressions

- Minimize complexity and depth for optimal performance.
- Changes to extension data classes may result in malformed expressions.
- Malformed expressions can lead to unexpected or empty results.

### Filter expressions

The examples for each filter expression below assume the following comment extension:

```csharp
public class MyCommentExtension {
  public int LuckyNumber {
    get;
    set;
  }
  public List<string> FavoriteTeams {
    get;
    set;
  }
  public DateTime Birthday {
    get;
    set;
  }
}
```

### Any expression

Use the `Any` expression to filter both single-value and multi-value extension fields by a list of values. As an example of using the `Any` expression with a single-value extension field, assume that you want to read all comments for which the single-value `LuckyNumber` extension field matches any of three drawn lucky numbers. The following code shows how this is done with the Any expression:

```csharp
var drawnLuckyNumbers = new List<long>{3, 7, 9};
var commentsWithDrawnLuckyNumbers = FilterExpressionBuilder<MyCommentExtension>.Field(ext => ext.LuckyNumber).Any(drawnLuckyNumbers);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{
  ExtensionFilter = commentsWithDrawnLuckyNumbers
};
```

As an example of using the Any expression with a multi-value extension field, assume that you want to read all comments for which the multi-value `favoriteTeams` extension field contains either "New England Patriots" or "Boston Red Sox". The following code shows how this is done with the `Any` expression.

```csharp
var mostFavoriteTeams = new List<string>{"New England Patriots", "Boston Red Sox"};
var commentsWithMostFavoriteTeams = FilterExpressionBuilder<MyCommentExtension>.Field(ext => ext.FavoriteTeams).Any(mostFavoriteTeams);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{
  ExtensionFilter = commentsWithMostFavoriteTeams
};
```

### Contains expression

The `Contains` expression can be used to filter both single-value and multi-value extension fields by a single value. As an example of using the `Contains` expression with a single-value extension field, assume that you want to read all comments for which the single-value `LuckyNumber` extension field matches drawn lucky number 7. The following code shows how this is done with the `Contains` expression:

```csharp
var luckyNumber = 7;
var commentsWithLuckNumber = FilterExpressionBuilder<MyCommentExtension>.Field(ext => ext.LuckyNumber).Contains(luckyNumber);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{
  ExtensionFilter = commentsWithLuckNumber
};
```

As an example of using the `Contains` expression with a multi-value extension field, assume that you want to read all comments for which the multi-value `favoriteTeams` extension field contains "Boston Celtics". The following code shows how this is done with the `Contains` expression.

```csharp
var favoriteTeam = "Boston Celtics";
var commentsWithFavoriteTeam = FilterExpressionBuilder<MyCommentExtension>.Field(ext => ext.FavoriteTeams).Contains(favoriteTeam);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{
  ExtensionFilter = commentsWithFavoriteTeam
};
```

### EqualTo expression

The `EqualTo` expression is used to filter documents by an extension field whose value equals a given value. The `EqualTo` expression in the following example will match any comments with a Birthday on new year 2000.

```csharp
var newYear2000 = new DateTime(2000, 1, 1);
var commentsWithMatchingBirthday = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).EqualTo(newYear2000);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{
  ExtensionFilter = commentsWithMatchingBirthday
};
```

### LessThanOrEqualTo expression

The `LessThanOrEqualTo` expression filters documents by an extension field whose value is less than or equal to a given value. The `LessThanOrEqualTo` expression in the following example will match any comments with a Birthday on or before new year 2000.

```csharp
var newYear2000 = new DateTime(2000, 1, 1);
var commentsWithMatchingBirthday = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).LessThanOrEqualTo(newYear2000);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{
  ExtensionFilter = commentsWithMatchingBirthday
};
```

### GreaterThanOrEqualTo expression

The `GreaterThanOrEqualTo` expression filters documents by an extension field whose value is greater than or equal to a given value. The `GreaterThanOrEqualTo` expression in the following example will match any comments with a Birthday on or after new year 2000.

```csharp
var newYear2000 = new DateTime(2000, 1, 1);
var commentsWithMatchingBirthday = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).GreaterThanOrEqualTo(newYear2000);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{
  ExtensionFilter = commentsWithMatchingBirthday
};
```

### LessThan expression

The `LessThan` expression in the following example matches any comments with a Birthday before 2000.

```csharp
var newYear2000 = new DateTime(2000, 1, 1);
var commentsWithMatchingBirthday = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).LessThan(newYear2000);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{
  ExtensionFilter = commentsWithMatchingBirthday
};
```

### GreaterThan expression

The `GreaterThan` expression filters documents by an extension field whose value exceeds a given value. The `GreaterThan` expression in the following example will match any comments with a Birthday after new year 2000.

```csharp
var newYear2000 = new DateTime(2000, 1, 1);
var commentsWithMatchingBirthday = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).GreaterThan(newYear2000);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{
  ExtensionFilter = commentsWithMatchingBirthday
};
```

### And expression

The `And` expression filters documents by one or more sub-expressions where a document is matched by all the sub-expressions. The `And` expression in the following example will match any comments with a Birthday in the year 2000.

```csharp
var startYear2000 = new DateTime(2000, 1, 1);
var endYear2000 = new DateTime(2000, 12, 31);
var commentsMatchingBirthday1 = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).GreaterThanOrEqualTo(startYear2000);
var commentsMatchingBirthday2 = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).LessThanOrEqualTo(endYear2000);
var commentsWithBirthdayInYear2000 = FilterExpressionBuilder<MyCommentExtension>.And(commentsMatchingBirthday1, commentsMatchingBirthday2);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{
  ExtensionFilter = commentsWithBirthdayInYear2000
};
```

### Or expression

The `Or` expression is used to filter documents by one or more sub-expressions where any of the sub-expressions matches a document. The `Or` expression in the following example will match any comments with a Birthday in year 2000 Or LuckyNumber 7.

```csharp
var startYear2000 = new DateTime(2000, 1, 1);
var endYear2000 = new DateTime(2000, 12, 31);
var commentsMatchingBirthday1 = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).GreaterThanOrEqualTo(startYear2000);
var commentsMatchingBirthday2 = FilterExpressionBuilder<MyCommentExtension>.Field(d => d.Birthday).LessThanOrEqualTo(endYear2000);
var commentsWithBirthdayInYear2000 = FilterExpressionBuilder<MyCommentExtension>.And(commentsMatchingBirthday1, commentsMatchingBirthday2);
var luckyNumber = 7;
var commentsWithLuckyNumber = FilterExpressionBuilder<MyCommentExtension>.Field(ext => ext.LuckyNumber).Contains(luckyNumber);
var theWinner = FilterExpressionBuilder<MyCommentExtension>.Or(commentsWithBirthdayInYear2000, commentsWithLuckyNumber);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{
  ExtensionFilter = theWinner
};
```

### Sort composites

Fields within extension data can also be used for sorting composite result sets. Sorting rules are defined using the `OrderBy` property of `CompositeCriteria`, accepting a collection of `SortInfo` instances.

`SortInfo` identifies the field and direction for sorting.

Consider an example where an application composes a comment with extension data with the following definition:

```csharp
public class MyCommentExtension {
  public int LuckyNumber {
    get;
    set;
  }
  public string FavoriteTeam {
    get;
    set;
  }
  public DateTime Birthday {
    get;
    set;
  }
}
```

The snippet below demonstrates the construction of an instance of `SortInfo`, targeting the LuckyNumber field of such an extension:

```csharp
var sortField = new SortField(FilterExpressionBuilder<MyCommentExtension>.Field(d => d.LuckyNumber));
var sortingRule = new SortInfo(sortField, true);
var criteria = new CompositeCriteria<Comment, MyCommentExtension>
{
  OrderBy = new List<SortInfo> { sortingRule }
};
```

In this example, an instance of `SortField` is constructed. It accepts a `FieldExpression` representing the LuckyNumber field of your extension data. Next, an instance of SortInfo is constructed to refer to this `SortField`, and assigned to the criteria as a sorting rule.

Sorting rules targeting extension data fields can be combined with those targeting standard platform entities.

## Asynchronous methods

Optimizely Community API services provide asynchronous method overloads (ending with `Async` suffix and returning a `.NET Task` object) for non-blocking operations. This improves application responsiveness and performance by allowing parallel execution of tasks. Developers can use C#'s `async` and `await` keywords.

For more details, refer to Microsoft's documentation for [Task-based Asynchronous Programming](https://msdn.microsoft.com/en-us/library/dd537609%28v=vs.110%29.aspx) and [Asynchronous Programming with async and await](https://msdn.microsoft.com/en-us/library/mt674882.aspx).
