Using the SitecoreAI Agent API Jobs Feature in Marketplace Apps

Created: 14 Dec 2025, last update: 14 Dec 2025

Using the SitecoreAI Agent API Jobs Feature in Marketplace Apps

This is the fourth blog about the SitecoreAI Agent API. In the previous posts I focused mainly on the MCP server and direct API usage. In this article I move one step further and look at how the Jobs feature can be used inside a Sitecore Marketplace app. When you build a Marketplace app, you often deal with automation, and maybe bulk updates, and long-running operations. In those scenarios, tracking what happened and being able to undo changes becomes much more important than when you make a single API call. This is exactly where the Jobs feature of the Agent API becomes useful.

Agent API Support in the Marketplace SDK
Recently, support for the Agent API was added to the Marketplace SDK.

Package: @sitecore-marketplace-sdk/xmc@0.3.0
Minor changes include:

• Added Agent API documentation
• Added new Agent API support in the xmc module

This means you can now call Agent API endpoints, including Jobs, directly from a Marketplace app using the SDK.

One important note:
If you develop for the Sitecore Marketplace, make sure you upgrade your Marketplace NPM packages to the latest versions. At the time of writing, the marketplace-starter project still uses ^0.2.0, which does not include the Agent API support. Without upgrading, the examples in this blog will not work.

Example: Using Jobs in a Marketplace App
Below is a small Next.js example using the Marketplace SDK. It shows how to:
• Use the Agent API from a Marketplace app
• Attach a jobId to both read and write operations
• List job operations
• Revert a job

For demo purposes, the same jobId is reused so you can clearly see how operations are grouped under one job.

import { ClientSDK } from "@sitecore-marketplace-sdk/client";
import { useState } from "react";

/**
 * JobTest Component
 * * Demonstrates XM Cloud Agent APIs for job management:
 * - Create content items with job tracking
 * - List job operations
 * - Revert job operations
 * * Note using over and over again the same jobid "job-1234" for demo purposes. The joblist will increase in size each time the createFolder is clicked.
 * * @param appContext - Application context containing resource access
 * @param pagesContext - Pages context containing page information
 * @param client - Marketplace SDK client instance
 */
export default function JobTest({
  appContext,
  pagesContext,
  client,
}: {
  appContext: any;
  pagesContext: any;
  client: ClientSDK | null;
}) {
  const [responseData, setResponseData] = useState<{
    componentsOnPage: any;
    createContentItem: any;
  } | null>(null);
  const [jobListData, setJobListData] = useState<any>(null);
  const [revertJobData, setRevertJobData] = useState<any>(null);

  /**
   * Creates a folder in XM Cloud and retrieves components on the current page.
   * Uses job tracking via x-sc-job-id header for audit and revert capabilities.
   */
  const createFolder = async () => {
    const sitecoreContextId = appContext.resourceAccess?.[0]?.context.preview;
    if (!sitecoreContextId) {
      console.error(
        "Sitecore Context ID not found in application context. Make sure your app is configured to use SitecoreAI APIs."
      );
      return;
    }

    const pageId = pagesContext?.pageInfo?.id;
    if (!pageId) {
      console.error("Page ID not found in application context.");
      return;
    }

    const responseComponentsOnPage = await client?.query("xmc.agent.pagesGetComponentsOnPage", {
      params: {
        headers: {
          "x-sc-job-id": "job-1234",
        },
        query: {
          sitecoreContextId,
        },
        path: {
          pageId: pageId,
        },
      },
    });

    const responseCreateContentItem = await client?.mutate("xmc.agent.contentCreateContentItem", {
      params: {
        headers: {
          "x-sc-job-id": "job-1234",
        },
        query: {
          sitecoreContextId,
        },
        body: {
          templateId: "{A87A00B1-E6DB-45AB-8B54-636FEC3B5523}",
          name: "New Content Item from marketplace jobtest",
          fields: {
            "__Version Name": "Created from marketplace jobtest",
          },
          parentId: pageId,
        },
      },
    });

    setResponseData({
      componentsOnPage: responseComponentsOnPage,
      createContentItem: responseCreateContentItem,
    });
  };

  /**
   * Retrieves all operations for a specific job ID.
   * Useful for tracking what actions were performed under a job.
   */
  const getJob = async () => {
    const sitecoreContextId = appContext.resourceAccess?.[0]?.context.preview;
    if (!sitecoreContextId) {
      console.error(
        "Sitecore Context ID not found in application context. Make sure your app is configured to use SitecoreAI APIs."
      );
      return;
    }

    const responseListJobOperations = await client?.query("xmc.agent.jobsListOperations", {
      params: {
        path: {
          jobId: "job-1234",
        },
        query: {
          sitecoreContextId,
        },
      },
    });

    setJobListData(responseListJobOperations);
  };

  /**
   * Reverts all operations performed under a specific job ID.
   * This allows you to undo all changes made during a job.
   */
  const revertJob = async () => {
    const sitecoreContextId = appContext.resourceAccess?.[0]?.context.preview;
    if (!sitecoreContextId) {
      console.error(
        "Sitecore Context ID not found in application context. Make sure your app is configured to use SitecoreAI APIs."
      );
      return;
    }

    const responseRevertJob = await client?.mutate("xmc.agent.jobsRevertJob", {
      params: {
        path: {
          jobId: "job-1234",
        },
        query: {
          sitecoreContextId,
        },
      },
    });

    setRevertJobData(responseRevertJob);
  };

  return (
    <div style={{ padding: "20px" }}>
      <div style={{ marginBottom: "20px" }}>
        <button 
          onClick={createFolder} 
          style={{ 
            padding: "10px 20px", 
            marginRight: "10px",
            backgroundColor: "#0078d4",
            color: "white",
            border: "none",
            borderRadius: "4px",
            cursor: "pointer"
          }}
        >
          Create Folder
        </button>
        <button 
          onClick={getJob} 
          style={{ 
            padding: "10px 20px",
            marginRight: "10px",
            backgroundColor: "#107c10",
            color: "white",
            border: "none",
            borderRadius: "4px",
            cursor: "pointer"
          }}
        >
          List Job Operations
        </button>
        <button 
          onClick={revertJob} 
          style={{ 
            padding: "10px 20px",
            backgroundColor: "#d83b01",
            color: "white",
            border: "none",
            borderRadius: "4px",
            cursor: "pointer"
          }}
        >
          Revert Job
        </button>
      </div>
      
      {responseData && (
        <div style={{ marginTop: "20px" }}>
          <h3>Components on Page Response</h3>
          <pre style={{ 
            background: "#f5f5f5", 
            padding: "15px", 
            borderRadius: "5px",
            overflow: "auto",
            maxHeight: "400px",
            marginBottom: "20px",
            fontSize: "12px"
          }}>
            {JSON.stringify(responseData.componentsOnPage, null, 2)}
          </pre>
          
          <h3>Create Content Item Response</h3>
          <pre style={{ 
            background: "#f5f5f5", 
            padding: "15px", 
            borderRadius: "5px",
            overflow: "auto",
            maxHeight: "400px",
            fontSize: "12px"
          }}>
            {JSON.stringify(responseData.createContentItem, null, 2)}
          </pre>
        </div>
      )}
      
      {jobListData && (
        <div style={{ marginTop: "20px" }}>
          <h3>Job Operations List</h3>
          <pre style={{ 
            background: "#f5f5f5", 
            padding: "15px", 
            borderRadius: "5px",
            overflow: "auto",
            maxHeight: "400px",
            fontSize: "12px"
          }}>
            {JSON.stringify(jobListData, null, 2)}
          </pre>
        </div>
      )}
      
      {revertJobData && (
        <div style={{ marginTop: "20px" }}>
          <h3>Revert Job Response</h3>
          <pre style={{ 
            background: "#f5f5f5", 
            padding: "15px", 
            borderRadius: "5px",
            overflow: "auto",
            maxHeight: "400px",
            fontSize: "12px"
          }}>
            {JSON.stringify(revertJobData, null, 2)}
          </pre>
        </div>
      )}
    </div>
  );
}

Using:

import JobTest from "@/src/components/Jobtest";
<JobTest appContext={appContext} pagesContext={pagesContext} client={client} />

Getting Started
If you are new to Marketplace development, make sure you follow the official quick start guide to initialize the SDK correctly:

Once the SDK is set up and upgraded to the latest version, you can start experimenting with the Agent API and Jobs feature directly from your app.

Closing Thoughts
In this blog I showed how to use the Jobs feature with the Marketplace SDK, including tracking, listing, and reverting job operations. If you want to deepen your understanding of the Agent API and how it works with other parts of the Sitecore ecosystem, you might also find these previous posts useful:
Exploring the SitecoreAI Agent API Jobs Feature: A deep dive into jobs, jobIds, revert logic, and real behavior with C# code.
Hide Wildcard URLs in sitemap.xml with the Sitecore MCP Server: Using MCP to automate sitemap fixes and explore API behavior in practice
Sitecore Agent API for Sitecore AI: An introduction to the core Agent API concepts and how they fit into the Sitecore AI tooling

Together, these posts provide a practical path from basic Agent API exploration to automation in Marketplace apps. I hope this helps you work more confidently with Sitecore automation APIs and build more robust, traceable solutions.