
When running multiple websites, perhaps one in Sitecore and another in a different CMS, you want consistent FAQ items across each brand. If someone updates an FAQ elsewhere, you need Sitecore to reflect that change immediately so visitors see the correct content.
How this works with the Sitecore Authoring API
When the other CMS, such as an Umbraco-powered site, saves or modifies its FAQ item, it sends a webhook containing the updated fields in JSON format. Our .NET application receives this payload, processes the data, and transforms it into a GraphQL mutation. Using the Sitecore Authoring API, we update the FAQ content directly in Sitecore. This approach does not rely on proprietary packages; it uses simple HTTP requests and a Bearer token for secure authentication.
The Sitecore Authoring API is a flexible tool that allows developers to manage content through GraphQL queries and mutations. This example is built for Sitecore XP 10.4, but the same Authoring API is also available in Sitecore XM Cloud, offering consistent capabilities for content integration across both platforms.
To learn more, check out the Sitecore documentation for the Authoring and Management GraphQL API. Additionally, Jason Wilkerson’s blog post, Sitecore Authoring API: A Complete Example, was a useful reference in understanding practical applications of this API.
Code example
Below is the essential code snippet from a .NET minimal API (though the concept works in any language or version):
// -------------------------------------------------------------------------
// Configuration - Sitecore
// -------------------------------------------------------------------------
string sitecoreIdentityServer = "https://sitecore-id-server.dev.local/";
string sitecoreClientId = "SitecorePassword";
string sitecoreClientSecret = "sitecore-client-secret";
string sitecoreUserName = @"sitecore\admin";
string sitecoreUserPass = "b";
string sitecoreGraphQLEndpoint = "https://sitecore-cm-server.dev.local/sitecore/api/authoring/graphql/v1";
string sitecoreFaqItemId = "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}";
// -------------------------------------------------------------------------
// Endpoint: Receive Umbraco Webhook -> Update Sitecore
// -------------------------------------------------------------------------
app.MapPost("/api/webhooks/umbraco", async (HttpContext context, ILogger<Program> logger) =>
{
// 1) Read the raw JSON body
var doc = await context.Request.ReadFromJsonAsync<JsonDocument>();
// 2) Parse JSON for the "FAQ" data
// Fields are in:
// properties.title
// properties.text.markup
string? title = null;
string? textMarkup = null;
var root = doc.RootElement;
// Title
if (root.TryGetProperty("properties", out var propsElem) &&
propsElem.TryGetProperty("title", out var titleElem))
{
title = titleElem.GetString();
}
// Text markup
if (propsElem.TryGetProperty("text", out var textElem) &&
textElem.TryGetProperty("markup", out var markupElem))
{
textMarkup = markupElem.GetString();
}
// 3) Update Sitecore using the parsed fields
var httpFactory = context.RequestServices.GetRequiredService<IHttpClientFactory>();
// (a) Get a token from Sitecore Identity
var sitecoreToken = await GetSitecoreTokenAsync(
httpFactory,
sitecoreIdentityServer,
sitecoreClientId,
sitecoreClientSecret,
sitecoreUserName,
sitecoreUserPass);
// (b) Define a GraphQL mutation that uses two variables: $title and $text
// We pass them into fields: [ { name:"Title", value: $title }, ... ].
var mutation = $@"
mutation UpdateItem($title: String, $text: String) {{
updateItem(
input: {{
itemId: ""{sitecoreFaqItemId}""
fields: [
{{ name: ""Title"", value: $title }},
{{ name: ""Text"", value: $text }}
]
}}
) {{
item {{
name
}}
}}
}}";
// (c) Build a request object with the query and variables
var reqPayload = new
{
query = mutation,
variables = new
{
title,
text = textMarkup
}
};
// (d) Serialize to JSON
var client = httpFactory.CreateClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", sitecoreToken);
var reqJson = JsonSerializer.Serialize(reqPayload);
var content = new StringContent(reqJson, Encoding.UTF8, "application/json");
// (e) Send the POST to Sitecore GraphQL
var response = await client.PostAsync(sitecoreGraphQLEndpoint, content);
var responseBody = await response.Content.ReadAsStringAsync();
logger.LogInformation("Sitecore item updated successfully");
return Results.Ok("Umbraco data used to update Sitecore successfully!");
});
// -----------------------------------------------------------------------
// Helper: Acquire a token from Sitecore Identity (Password Grant)
// -----------------------------------------------------------------------
static async Task<string?> GetSitecoreTokenAsync(
IHttpClientFactory httpFactory,
string identityServer,
string clientId,
string clientSecret,
string userName,
string userPass)
{
using var tokenClient = httpFactory.CreateClient();
tokenClient.BaseAddress = new Uri(identityServer);
var req = new PasswordTokenRequest
{
Address = "/connect/token",
ClientId = clientId,
ClientSecret = clientSecret,
GrantType = IdentityModel.OidcConstants.GrantTypes.Password,
Scope = "openid sitecore.profile sitecore.profile.api",
UserName = userName,
Password = userPass
};
var resp = await tokenClient.RequestPasswordTokenAsync(req);
return resp.AccessToken;
}
You can view all the code in this Gist.
Key Steps:
- Parse JSON from the Umbraco webhook: Use
ReadFromJsonAsync<JsonDocument>()
. - Extract Fields: For example, you might look for
"title"
or"text"
in the incoming payload. - Get Token: A typical password-based request to
POST /connect/token
with ClientId, ClientSecret, etc. - GraphQL Mutation: Send that via an HTTP
POST
tohttps://my-sitecore-cm/sitecore/api/authoring/graphql/v1
withAuthorization: Bearer <token>
.
Short demo video
In the demo, you’ll see how content synchronization works between Sitecore and Umbraco using the Sitecore Authoring API and the Umbraco Management API: https://youtu.be/QHxpJ2EozBU
Conclusion
This technique relies on standard webhooks and GraphQL calls, not official Sitecore NuGet packages. You can implement it in any language that can make HTTP requests. By automating FAQs in real time, you ensure visitors see consistent content across different brand sites even if they are on different platforms.
For the other direction, see how content edits in Sitecore can be synced back to Umbraco using the Umbraco Management API:
Real-Time FAQs: Updating Umbraco with the Management API