What is your developer-dependent CMS actually costing you? Calculate your costs and get a full report
What is your developer-dependent CMS actually costing you? Calculate your costs and get a full report
Introduction
How Management API writes are queued as batches: poll batch status, read item errors, create batches from your own item list, publish with nested content, and the JavaScript and .NET SDK methods.
Most writes in the Management API don't happen during your request. Saves, deletes and workflow operations (publish, unpublish, approve, decline, request approval) are queued as a batch, and the API answers with a batch ID. The change happens when Agility processes the batch, usually within seconds. This page explains that lifecycle: how a batch starts, how to poll it, how to read item-level errors, and how to act on many items at once.
If you use the JavaScript or .NET Management SDK, the SDK waits for batches for you by default. Read this page when you turn that waiting off, call the REST API directly, or need to handle partial failures.
The Management API's Batch tag has seven operations. None of the paths has a {locale} segment: a batch belongs to the instance, and each item in it carries its own locale.
| Operation | Endpoint | Returns |
|---|---|---|
| Create a batch from a list of items | POST /api/v1/instance/{guid}/batch | BatchCreateResult |
| Get a batch's status and items | GET /api/v1/instance/{guid}/batch/{id} | Batch |
| Publish every item in a batch | POST /api/v1/instance/{guid}/batch/{id}/publish | A batch ID |
| Unpublish every item in a batch | POST /api/v1/instance/{guid}/batch/{id}/unpublish | A batch ID |
| Approve every item in a batch | POST /api/v1/instance/{guid}/batch/{id}/approve | A batch ID |
| Decline every item in a batch | POST /api/v1/instance/{guid}/batch/{id}/decline | A batch ID |
| Request approval for every item in a batch | POST /api/v1/instance/{guid}/batch/{id}/request-approval | A batch ID |
Two more operations, on the ContentItem and Page tags, run one workflow operation on many items in a single batch:
| Operation | Endpoint |
|---|---|
| Workflow operation on many content items | POST /api/v1/instance/{guid}/{locale}/item/batch-workflow?contentIDs=101,102&operation=Publish |
| Workflow operation on many pages | POST /api/v1/instance/{guid}/{locale}/page/batch-workflow?pageIDs=7,8&operation=Publish |
operation is one of Publish, Unpublish, Approve, Decline or RequestApproval. Each call accepts at most 250 IDs.
Full request and response schemas are in the Management API reference.
POST batch returns a BatchCreateResult with one or more batch IDs.GET batch/{id} until batchState is 3 (Processed).items[].errorMessage.batchState | Name | Meaning |
|---|---|---|
0 | None | |
1 | Pending | Queued, not started |
2 | InProcess | Being processed |
3 | Processed | Finished. Check the items for errors. |
4 | Deleted | The batch was deleted |
The state names come from the BatchState enum in both SDKs. A newly created batch ID can return 404 for a moment before it exists, so treat an early 404 as "not created yet" rather than as a failure.
GET batch/{id} takes an expandItems query parameter (default true). Pass expandItems=false while you poll to get only the batch summary, then fetch once with items when it is processed.
curl -H "Authorization: Bearer $AGILITY_TOKEN" \
"https://mgmt.aglty.io/api/v1/instance/$GUID/batch/$BATCH_ID?expandItems=false"
Useful fields on the Batch response:
| Field | What it tells you |
|---|---|
batchState | Where the batch is in its lifecycle (see above) |
percentComplete, numItemsProcessed, batchItemCount | Progress through the batch |
statusMessage | A status message for the batch |
errorData | Error information for the batch as a whole |
abortYN | Whether the batch was aborted |
items | The items, when expandItems is true |
Each entry in items has itemID, itemType, languageCode, itemTitle and errorMessage. An item with an errorMessage failed.
Use the host for your instance's region (for example mgmt.aglty.io for a -u instance). The region table and authentication options are in Getting Started.
Every batch endpoint only queues work. Agility checks your permission on each item when it processes the batch, so an item you can't act on fails inside the batch while the other items go ahead. The request that created the batch still succeeds. Always check items[].errorMessage before you report success.
POST batch creates a batch for an explicit list of pages and content items and queues it.
curl -X POST -H "Authorization: Bearer $AGILITY_TOKEN" -H "Content-Type: application/json" \
"https://mgmt.aglty.io/api/v1/instance/$GUID/batch" \
-d '{
"batchName": "Spring campaign",
"operation": "Publish",
"comments": "Campaign launch",
"items": [
{ "itemID": 1201, "itemType": 1, "languageCode": "en-us" },
{ "itemID": 3456, "itemType": 2, "languageCode": "en-us" }
]
}'
| Property | Notes |
|---|---|
operation | Publish, Unpublish, Approve, Decline or RequestApproval |
items | At least one item. itemID is a page ID or a content ID of an existing item. |
itemType | 1 Page, 2 ContentItem (values from the BatchItemType enum) |
languageCode | The item's locale, for example en-us |
batchName | Optional. Defaults to "Custom Batch". |
isPrivate | Optional. Defaults to true (visible only to the creator). |
comments | Optional notes, stored with the batch |
The processNow query parameter (default true) queues the batch for processing immediately.
A list longer than one batch holds is split across several batches instead of being rejected. The response tells you what happened:
{
"batchIDs": [90121, 90122],
"batchCount": 2,
"itemCount": 400,
"failedItemCount": 0
}
Poll every ID in batchIDs, not just the first. failedItemCount counts items that were not queued because the batch carrying them failed to create. It is normally 0, and itemCount + failedItemCount always equals the number of items you sent.
In the Content Manager, publishing an item or page now publishes its nested linked content by default (see Previewing, Publishing, and Content States). The Management API keeps the two behaviors on separate routes:
| Endpoint | What it publishes |
|---|---|
GET /{locale}/item/{contentID}/publish | The content item only |
GET /{locale}/page/{id}/publish | The page only |
POST /{locale}/item/{contentID}/publish-cascade | The content item and its one-level nested content (non-shared containers its fields point at) |
POST /{locale}/page/{id}/publish-cascade | The page, its components, and their one-level nested content |
GET /{locale}/item/{contentID}/cascade-items | Read-only preview of what a cascading publish of the item would include, as a tree |
GET /{locale}/page/{id}/cascade-items | Read-only preview of what a cascading publish of the page would include, as a tree |
The publish-cascade routes can create more than one batch, so they return a BatchCreateResult. Poll every batch ID.
To publish only part of the tree, read cascade-items, pick the nodes you want, and submit them with POST batch. The preview is not filtered by workflow state and is not capped, so it can show items that a cascading publish would skip.
@agility/management-sdk)Batch methods are on apiClient.batchMethods: getBatch, publishBatch, unpublishBatch, approveBatch, declineBatch and requestApprovalBatch. Write and workflow methods on contentMethods and pageMethods (including batchWorkflowContent and batchWorkflowPages) wait for their batch by default. Pass returnBatchId: true to get the batch ID back immediately and poll it yourself.
import * as mgmtApi from "@agility/management-sdk"
const options = new mgmtApi.Options()
options.token = process.env.AGILITY_TOKEN
const apiClient = new mgmtApi.ApiClient(options)
const guid = "<<your-instance-guid>>"
// Queue a bulk publish and get the batch ID back immediately (as a one-element array)
const [batchId] = await apiClient.contentMethods.batchWorkflowContent(
[101, 102, 103],
guid,
"en-us",
mgmtApi.WorkflowOperationType.Publish,
true, // returnBatchId
)
// Later: read the batch with its items and look for failures
const batch = await apiClient.batchMethods.getBatch(batchId, guid, true)
if (batch.batchState === mgmtApi.BatchState.Processed) {
const failed = batch.items.filter((i) => i.errorMessage)
console.log(`${failed.length} item(s) failed`, failed)
}
using Agility.Management.Sdk;
using Agility.Management.Sdk.Models;
using var client = new AgilityManagementClient(new AgilityManagementOptions
{
AccessToken = Environment.GetEnvironmentVariable("AGILITY_TOKEN"),
});
var guid = "<<your-instance-guid>>";
// Queue a bulk publish without waiting
var queued = await client.Content.BatchWorkflowContentItemsAsync(
guid, "en-us", [101, 102, 103], WorkflowOperationType.Publish, waitForBatch: false);
// Later: wait for it. Throws AgilityBatchException if any item failed.
try
{
Batch batch = await client.Batches.WaitForBatchAsync(guid, queued.BatchId);
}
catch (AgilityBatchException ex)
{
foreach (var failed in ex.Batch?.Items?.Where(i => i.ErrorMessage is not null) ?? [])
Console.WriteLine($"{failed.ItemID}: {failed.ErrorMessage}");
}
When the JavaScript SDK waits for a batch, it stops waiting once the batch is processed. Some methods, such as batchWorkflowContent, throw if the processed batch reports errorData, but the SDK does not check each item's errorMessage for you. Read the batch with getBatch and check the items yourself when partial failure matters. The polling interval and attempt limit are the duration and retryCount options described in Getting Started.
The JavaScript SDK does not yet have methods for POST batch, cascade-items or publish-cascade. Call those endpoints directly.
Agility.Management.SDK 2.0)In 2.0, batches are on client.Batches:
| Method | Endpoint |
|---|---|
GetBatchAsync(guid, batchId, expandItems) | GET batch/{id} |
CreateBatchAsync(guid, request, processNow) | POST batch, returns BatchCreateResult |
PublishBatchAsync, UnpublishBatchAsync, ApproveBatchAsync, DeclineBatchAsync, RequestApprovalBatchAsync | POST batch/{id}/... |
WaitForBatchAsync(guid, batchId) | Polls until the batch is processed |
The cascade operations are on the content and pages clients: client.Content.GetCascadeItemsAsync, client.Content.PublishContentItemCascadeAsync, client.Pages.GetCascadeItemsAsync and client.Pages.PublishPageCascadeAsync. The bulk workflow operations are client.Content.BatchWorkflowContentItemsAsync and client.Pages.BatchWorkflowPagesAsync.
Every batch-producing method has a waitForBatch parameter (default true) and returns a BatchResult. While waiting, the SDK checks the batch every 3 seconds, treats a 404 in the first 30 seconds as "not created yet", and gives up after 15 minutes with AgilityBatchTimeoutException. A processed batch with failed items, or an aborted or deleted batch, throws AgilityBatchException. All three settings are on BatchPolling in the client options. See Management SDK - Intro for the details.
// Publish a hand-picked set of items as one or more batches
var created = await client.Batches.CreateBatchAsync(guid, new CreateBatchWithItemsRequest
{
BatchName = "Spring campaign",
Operation = WorkflowOperationType.Publish,
Items =
[
new AddBatchItemRequest { ItemID = 1201, ItemType = BatchItemType.Page, LanguageCode = "en-us" },
new AddBatchItemRequest { ItemID = 3456, ItemType = BatchItemType.ContentItem, LanguageCode = "en-us" },
],
}, processNow: true);
foreach (var id in created.BatchIDs ?? [])
await client.Batches.WaitForBatchAsync(guid, id);
batch-workflow call queues one batch for up to 250 items.BatchCreateResult can name several.