HomeDev GuideAPI Reference
Dev GuideAPI ReferenceUser GuideGitHubNuGetDev CommunitySubmit a ticketLog In
GitHubNuGetDev CommunitySubmit a ticket


Describes the process of creating a content approval.

IApprovalRepository is the base interface for saving, deleting, and listing approvals and their decisions. IApprovalEngine is built on top of IApprovalRepository to streamline the handling of approvals. Use the repository for listing approvals and use the engine for handling approvals. The engine also raises events that can be hooked up in IApprovalEngineEvents.

Hook up events

public class ApprovalLogger: IInitializableModule {
  private IApprovalEngineEvents _approvalEngineEvents;

  public void Initialize(InitializationEngine context) {
    _approvalEngineEvents = context.Locate.Advanced.GetInstance < IApprovalEngineEvents > ();
    _approvalEngineEvents.Approved += OnApproved;

  public void Uninitialize(InitializationEngine context) => _approvalEngineEvents.Approved -= OnApproved;

  private void OnApproved(ApprovalEventArgs e) => LogManager.GetLogger(typeof (ApprovalLogger)).Debug("Approve");

Start an Approval

Content approval is not started by saving an approval but by saving a content item with SaveAction.RequestApproval. This automatically creates and saves a ContentApproval for this content item, if a definition can be resolved.

IContent content;
IContentRepository contentRepository;

var approvalContentLink = contentRepository.Save(content, SaveAction.RequestApproval);IContent content;
    IContentRepository contentRepository;
    var approvalContentLink = contentRepository.Save(content, SaveAction.RequestApproval);

Abort an approval

This deletes an approval and raises an aborted event:

Approval approval;
IApprovalEngine approvalEngine;
  await approvalEngine.AbortAsync(approval.ID, "user");

Make a decision

Use the engine to decide whether to approve or reject a step or the whole approval. You can add an optional comment to explain the reason for the decision. If the decision finishes the approval (approves the last step or rejects a step), this comment is saved on the approval as CompletedComment.

Approval approval;
IApprovalEngine approvalEngine;

// Approve a step if user is part of the current definition step
await approvalEngine.ApproveAsync(approval.ID, "user", 1, ApprovalDecisionScope.Step);

// Reject a step if user is part of the current definition step, adding a comment
await approvalEngine.RejectAsync(approval.ID, "user", 1, ApprovalDecisionScope.Step, "This is why I did it");

// Force approve a step whether the user is part of the current definition step or not
await approvalEngine.ApproveAsync(approval.ID, "user", 1, ApprovalDecisionScope.ForceStep);

// Force approve the whole approval 
await approvalEngine.ApproveAsync(approval.ID, "user", 1, ApprovalDecisionScope.Force);

There are also several more explicitly named extension methods to the engine that can be used, for example ApproveStepAsync and ForceApproveAsync.

List approvals

Use the GetAsync or GetItemsAsync methods on IApprovalRepository to get specific approvals using ID or ContentReference:

using EPiServer.Approvals.ContentApprovals;

ContentReference contentLink;
IApprovalRepository approvalRepository;

var approval = await approvalRepository.GetAsync(contentLink);

The ListAsync method takes an ApprovalQuery or ContentApprovalQuery object which searches the approvals based on the specified query data and returns a filtered list. This list can be paged.

This example gets approvals in review for a user based on a specific definition.

using EPiServer.Approvals.ContentApprovals;

ContentApprovalDefinition definition;
IApprovalRepository approvalRepository;

var approvals = await approvalRepository.ListAsync(new ContentApprovalQuery {
  Username = "user",
    Status = ApprovalStatus.InReview,
    DefinitionID = definition.ID

This example lists decisions made for approval:

Approval approval;
IApprovalRepository approvalRepository;

var decisions = await approvalRepository.ListDecisionsAsync(approval.ID);