How AI is applied across API Evangelist and APIs.io. Read my AI disclosure →
API Evangelist API Evangelist
Discovery
Learnings
Guidance
Toolbox
Alignment
API Evangelist LLC

Nutanix v4 API Batches: A Technical Use Case

calendar_today April 13, 2026 person Chris Rasmussen domain nutanix

Introduction

In July 2024, we published a two-part series covering the technical usage of Nutanix v4 API Batch operations. That series focused specifically on CREATE and MODIFY operations in the first part, and batch ACTIONS in the second part, both using the Nutanix v4 Python SDK.

In today’s article we’ll look at the “why”, as well as a potential real-world use case for the Nutanix v4 batch APIs provided by the prism namespace. To achieve this, we’ll demonstrate that use case with a practical, REST API example.

If you are new to the Nutanix v4 APIs, see the Nutanix v4 API User Guide for getting started info.

Why?

To begin, consider the following scenario.

  1. A request is received that requires the creation of 10 virtual machines. For the purposes of this article, assume the following:
    • 2 of the new virtual machines are destined to be database servers
    • 8 of the new virtual machines are destined to be web servers
  2. The approaches outlined here apply even when the request is significantly larger

Note: We’ll focus only on the deployment of the virtual machine infrastructure only and not the deployment of the database or web server software.

Option 1: The “old” way

Depending on the infrastructure system or API versions in use, it may be possible to achieve the desired using 10 separate API requests. This requires the following steps:

  • Construction of 10 individual REST API payloads.
  • Submission of 10 individual REST API requests.
  • A minimum of 10 individual REST API requests to check on the status of each entity create request, although this assumes each related task is only checked once.
  • In total, a minimum of 30 individual API requests to deploy 10 new virtual machines.

While this will achieve the desired result, it will generate additional complexity and the submission of additional network traffic in the form of individual requests. In some environments, the minimization of unnecessary network traffic is a key requirement; 10 individual requests may not meet this requirement. This can be especially important in remotely-managed or high-latency networks.

Repetitive Requests

For each VM created here, the payload would need to be similar to this example; the trimmed section would contain environment specific details such as storage configuration, network configuration (etc).

{
    "name": "db1",
    "description": "batchvm_db{vm_number}",
    "cluster": {
        "extId": "577251cb-351c-4768-a869-2766fafc3289"
    }
    ...
}

At first glance this looks like a simple payload – and it is! However, it would need to be modified and sent as 10 individual requests for this approach to work. Because batching of API requests is a direct answer to the inefficiencies of repeated requests, we can do better.

Option 2: The “new” way

Batch processing can alleviate the complex task of managing and monitoring 10 individual requests by doing exactly as the name suggests: grouping the requests into batches i.e. smaller, more manageable chunks that can be easily monitored, up to 500 entities at a time.

For our example, this requires building a single payload for the database servers and a single payload for the web servers. Then, instead of sending 2 requests for the database servers and 8 requests for the web servers, we can build and send a single batch request that encapsulates all 10 requests for the 10 required servers.

Note: All batch operations are managed by the prism v4 API namespace. The operations within the batch request will define which APIs are used for each individual request; in this case, create VM from the vmm namespace.

The Solution

Assumptions

This article is not intended as a getting started guide for the Nutanix v4 APIs. As such, the demo cluster extId: 577251cb-351c-4768-a869-2766fafc3289 is already available. In a production scenario this would likely be obtained by using the clustermgmt v4 API namespace to get the details of the VM host cluster.

Payload metadata

Prism batch requests consist of two main parts:

  1. Metadata: the per-batch metadata e.g. the type of request, API request path for each subtask and what to do if an error occurs. The metadata object also contains action-specific details if the batch action acts on existing entities. This could be updating a VM or adding a VM to a category.
  2. Data: the per-entity data e.g. for creating a VM this would include the VM name, description and spec properties such as CPU configuration, RAM, storage and network details.

Here’s an example of the request metadata object for our 10 VM request.

{
    "metadata": {
        "action": "CREATE",
        "name": "10 VMs created with Nutanix v4.2 APIs",
        "uri": "/api/vmm/v4.2/ahv/config/vms",
        "shouldStopOnError": false,
        "chunkSize": 1
    },

This metadata clearly shows properties matching those described above:

  • action: Create an entity/entities.
  • name: The name of the batch request.
  • uri: The URI/endpoint to use for each subtask; in this example the path is the vmm namespace’s VM create endpoint.
  • shouldStopOnError: For our example, we do NOT want to stop the entire batch process if one of the VM create requests should fail. If there are VM dependencies that would cause problems later, this would be set to true
  • chunkSize: How many VMs to create at a time. Note chunkSize is not intended as a performance enhancement.

Payload data

With the request metadata built, we can move on to building the data part of the request. The data list specifies the spec for each affected entity – new VMs in our example.

How the user builds the data list will depend on the requirements. This could be a script loop or an imported JSON file. For our example, let’s assume the VM specs are as follows:

  • Database VMs
    • name: db{vm_number} i.e. db1 and db2
    • description: batchvm_db{vm_number}
    • vRAM in GiB: 1
    • All other specs are left as default
  • Web server VMs:
    • name: web{vm_number} i.e. web1web8
    • description: batchvm_web{vm_number}
    • vRAM in GiB: 1
    • All other specs are left as default

Programmatically, it wouldn’t make much sense to manually type or create one large JSON for these specs. In a script or app, the payload would be built iteratively, that is, a loop that builds a single VM payload at each iteration and appends it to the data list.

This approach would produce a JSON payload data list similar to this example:

"payload": [
    {
        "data": {
            "name": "db1",
            "description": "batchvm_db1",
            "memory_size_bytes": 1073741824,
            "cluster": {
                "extId": "577251cb-351c-4768-a869-2766fafc3289"
            }
        }
    },
    ...
    {
        "data": {
            "name": "web1",
            "description": "batchvm_web1",
            "memory_size_bytes": 1073741824,
            "cluster": {
                "extId": "577251cb-351c-4768-a869-2766fafc3289"
            }
        }
    },
    ...
]

Send the request batch

With the batch payload constructed, it is now a simple case of sending the request as follows.

  • URL: https://{ {pc_ip} }:9440/api/prism/v4.2/operations/$actions/batch
  • Method: POST
  • Payload: The complete JSON payload constructed so far; a copy of the complete payload will be in Appendix A at the end of this article.

So … why?

Using legacy methods, every request’s response would need to be parsed, the task extId for that task extracted, and the prism namespace’s tasksApi used to gain visibility into the results of that task. As discussed earlier, the “why” of batches is to increase efficiency and to gain a better insight into large collections of related requests.

The Nutanix v4 API batch operations avoid the need to process a potential multitude of individual requests, a process that can take time and comparatively manual effort.

Batch Success

Let’s look at the response from a successful batch request. The main response contains a single task ID i.e. the batch task itself:

{
    "data": {
        "$objectType": "prism.v4.config.TaskReference",
        "$reserved": {
            "$fv": "v4.r2"
        },
        "extId": "ZXJnb24=:3cade39c-6199-470f-5bf5-2cea80f6f3a2"
    }
}

Using the prism namespace’s tasks endpoints, the task details can be quickly retrieved and parsed; the full response has been trimmed for readability.

{
    "data": {
        "extId": "ZXJnb24=:657959ff-b4ff-4b62-4a46-b2f14d24ed0b",
        "operation": "BATCH-CREATE",
        "operationDescription": "10 VMs created with Nutanix v4.2 APIs",
        "createdTime": "2026-03-19T05:30:08.911013Z",
        "startedTime": "2026-03-19T05:30:08.921785Z",
        "completedTime": "2026-03-19T05:30:20.56036Z",
        "progressPercentage": 100,
        "entitiesAffected": [
            {
                "extId": "5d8f74b9-ac76-4b1f-5a21-533d47ee4183",
                "rel": "vmm:ahv:config:vm",
                "name": "batch_vm_db1",
                "$reserved": {
                    "$fv": "v4.r2"
                },
                "$objectType": "prism.v4.config.EntityReference"
            },
            ...
        ],
        "subTasks": [
            {
                "$reserved": {
                    "$fv": "v4.r2"
                },
                "$objectType": "prism.v4.config.TaskReferenceInternal",
                "extId": "ZXJnb24=:3ea4ab04-0d4b-512e-9830-7cfeff99df44",
                "href": "https://10.0.0.1:9440/api/prism/v4.2/config/tasks/ZXJnb24=:3ea4ab04-0d4b-512e-9830-7cfeff99df44",
                "rel": "subtask"
            },
            ...
        ],
        ...
        "numberOfSubtasks": 10,
        "numberOfEntitiesAffected": 10,
        ...
        "status": "SUCCEEDED",
        ...
    },
    ...
    "metadata": {
        "flags": [
            {
                ...
                "name": "hasError",
                "value": false
            },
            ...
        ],
        ...
    }
}

The key points to notice here are as follows.

  • All 10 VMs have been created with a single request
  • All 10 VMs were successfully created, with related entity information available in the entitiesAffected list
  • For each of the 10 new VMs, the related VM creation details are available in the subTasks list
  • Within the metadata object, the hasError flag indicates there were no errors encountered during the parent batch request
  • If required, you can still parse the full response, get each individual task ID and request that task for more detailed per-entity information. For example, if we request the task relating to the web2 VM, the response contains the following details (trimmed for readability):
{
    "data": {
        "extId": "ZXJnb24=:3ea4ab04-0d4b-512e-9830-7cfeff99df44",
        "operation": "CreateVm",
        "operationDescription": "Create VM",
        "createdTime": "2026-03-19T05:30:19.320126Z",
        "startedTime": "2026-03-19T05:30:19.327126Z",
        "completedTime": "2026-03-19T05:30:19.858228Z",
        "progressPercentage": 100,
        "entitiesAffected": [
            {
                "extId": "30465c06-517c-4acd-559d-5e5e9a9bf6db",
                "rel": "vmm:ahv:config:vm",
                "name": "web2",
                "$reserved": {
                    "$fv": "v4.r2"
                },
                "$objectType": "prism.v4.config.EntityReference"
            }
        ],
        ...
        "status": "SUCCEEDED",
    }
    ...
    "metadata": {
        "flags": [
            {
                ...
                "name: "hasError",
                "value": false
            },
            ...
        ]
    }
}

Batch Error

Conversely, introducing an intentional error into the batch details returns a clear indication that something failed. By setting the shouldStopOnError property to false, the entire batch will continue even if one or more of the VM creation subtasks fails. For example, setting the cluster extId to an invalid value will respond as follows; this time we’ll just show the relevant parts of the response.

{
    "data": {
        "entitiesAffected": [
           ...
        ],
        ...
        "errorMessages": [
            {
                "$reserved": {
                    "$fv": "v4.r2"
                },
                "$objectType": "prism.v4.error.AppMessage",
                "message": "Operation failed due to legacy error and 'legacyErrorMessage' should be referred to for details",
                "severity": "ERROR",
                "code": "TSKS-20801",
                "locale": "en_US",
                "errorGroup": "LEGACY_ERROR"
            }
        ],
        "legacyErrorMessage": "1 subtask has failed.",
        ...
        "numberOfSubtasks": 10,
        "numberOfEntitiesAffected": 9,
        ...
    ...
}

Here we can see that of the 10 entities that were requested, 9 were “affected”, indicating that 1 of the requested entities could not be processed. The entitiesAffected list then be parsed to easily find out which entity could not be processed.

Important note: In the current release of the Nutanix v4 APIs the complete failed task details are not yet available via API. This is a known limitation, although task details can still be observed in the Prism UI.

Conclusion

As shown in this article, payload batching can be a more efficient way of handling large related entity operations compared to legacy approaches. Even though this article demonstrated the batch creation of “only” 10 new VMs, up to 500 entities can be batched at a time. In this example, a single request initiated the batch operation and a single request obtained details of that batch operation. That’s a total of only 2 requests, vs a potential total of 20 requests for legacy methods.

For Nutanix v4 REST API prism namespace batching operations, see Batches in the Nutanix v4 API documentation.

Appendix A: Complete JSON Payload

{
    "metadata": {
        "action": "CREATE",
        "name": "10 VMs created with Nutanix v4.2 APIs",
        "uri": "/api/vmm/v4.2/ahv/config/vms",
        "shouldStopOnError": false,
        "chunkSize": 1
    },
    "payload": [
        {
            "data": {
                "name": "db1",
                "description": "batchvm_db1",
                "memory_size_bytes": 1073741824,
                "cluster": {
                    "extId": "577251cb-351c-4768-a869-2766fafc3289"
                }
            }
        },
        {
            "data": {
                "name": "db2",
                "description": "batchvm_db2",
                "memory_size_bytes": 1073741824,
                "cluster": {
                    "extId": "577251cb-351c-4768-a869-2766fafc3289"
                }
            }
        },
        {
            "data": {
                "name": "web1",
                "description": "batchvm_web1",
                "memory_size_bytes": 1073741824,
                "cluster": {
                    "extId": "577251cb-351c-4768-a869-2766fafc3289"
                }
            }
        },
        {
            "data": {
                "name": "web2",
                "description": "batchvm_web2",
                "memory_size_bytes": 1073741824,
                "cluster": {
                    "extId": "577251cb-351c-4768-a869-2766fafc3289"
                }
            }
        },
        {
            "data": {
                "name": "web3",
                "description": "batchvm_web3",
                "memory_size_bytes": 1073741824,
                "cluster": {
                    "extId": "577251cb-351c-4768-a869-2766fafc3289"
                }
            }
        },
        {
            "data": {
                "name": "web4",
                "description": "batchvm_web4",
                "memory_size_bytes": 1073741824,
                "cluster": {
                    "extId": "577251cb-351c-4768-a869-2766fafc3289"
                }
            }
        },
        {
            "data": {
                "name": "web5",
                "description": "batchvm_web5",
                "memory_size_bytes": 1073741824,
                "cluster": {
                    "extId": "577251cb-351c-4768-a869-2766fafc3289"
                }
            }
        },
        {
            "data": {
                "name": "web6",
                "description": "batchvm_web6",
                "memory_size_bytes": 1073741824,
                "cluster": {
                    "extId": "577251cb-351c-4768-a869-2766fafc3289"
                }
            }
        },
        {
            "data": {
                "name": "web7",
                "description": "batchvm_web7",
                "memory_size_bytes": 1073741824,
                "cluster": {
                    "extId": "577251cb-351c-4768-a869-2766fafc3289"
                }
            }
        },
        {
            "data": {
                "name": "web8",
                "description": "batchvm_web8",
                "memory_size_bytes": 1073741824,
                "cluster": {
                    "extId": "577251cb-351c-4768-a869-2766fafc3289"
                }
            }
        },
        {
            "data": {
                "name": "web9",
                "description": "batchvm_web9",
                "memory_size_bytes": 1073741824,
                "cluster": {
                    "extId": "577251cb-351c-4768-a869-2766fafc3289"
                }
            }
        }
    ]
}

open_in_new Read original post