Long-running operations
Occasionally, a service may need to expose an operation that takes a significant amount of time to complete. In these situations, it is often a poor user experience to simply block while the task runs; rather, it is better to return some kind of promise to the user, and allow the user to check back in later.
The long-running request pattern is roughly analogous to a Future in Python
or Java, or a Node.js Promise. Essentially, the user is given a token
that can be used to track progress and retrieve the result.
Guidance
Section titled “Guidance”Operations that might take a significant amount of time to complete:
- must return
202 Acceptedon successful submission to indicate the request has been accepted for processing. - must return an
Operationobject (see Interface Definitions) in the response body. - must match other AEP guidance that would apply to the method otherwise.
- may include a Location header pointing to the operation status endpoint.
Example:
POST /documents/123/publications
202 AcceptedLocation: /operations/op_abc123xyzContent-Type: application/json
{ "id": "op_abc123xyz", "state": "pending", "metadata": { "createdTime": "2025-12-02T10:30:00Z" }}Querying an operation
Section titled “Querying an operation”The service must provide a GET /operations/{operationId} endpoint to
query the status of the operation. This endpoint:
- must return
200 OKwith anOperationobject (see Interface Definitions) when the operation exists. - must return
404 Not Foundwhen the operation does not exist (e.g., expired or invalid ID).
The service should provide a GET /operations endpoint to list operations.
This endpoint:
- may support filtering.
- must follow standard pagination guidelines if implemented.
The Operation object returned:
- must include the current
stateof the operation. - should include progress information in the
metadatafield when available (e.g., percentage complete, items processed). - must include the operation result in the
resultfield when state is succeeded. - must include error details in the
errorsarray when state is failed.
APIs may include additional state values if needed, but must document them clearly.
Cancellation
Section titled “Cancellation”APIs may support cancelling long-running operations when feasible. Cancellation:
- must be implemented via
POST /operations/{operationId}:cancel. - must return
200 OKwith the updatedOperationobject if the operation was successfully canceled. - must return
404 Not Foundif the operation does not exist. - may not take effect immediately; the operation
stateshould transition to canceled once cancellation is complete.
Not all operations can be safely canceled. APIs must document which operations support cancellation.
Parallel requests
Section titled “Parallel requests”A resource may accept multiple requests that will work on it in parallel but is not obligated to do so:
- Resources that accept multiple parallel requests may place them in a queue rather than work on the requests simultaneously.
- A resource that does not permit multiple requests in parallel (denying any
new request until the one that is in progress finishes) must return
409 Conflictif a user attempts a parallel request, and include an error message explaining the situation.
Expiration
Section titled “Expiration”APIs may allow their operation resources to expire after sufficient time has elapsed after the request completed.
- Expired operations should return
404 Not Foundor410 Gonewhen queried. - The expiration policy must be documented.
- APIs should retain operation records long enough for clients to retrieve results, even with retry delays.
Errors
Section titled “Errors”Errors that prevent a long-running request from starting must return an error response, similar to any other method.
Errors that occur during the operation’s execution must be reflected in
the Operation object with state: "failed" and detailed error information in
the errors array.
Interface Definitions
Section titled “Interface Definitions”Operation: type: object description: Represents a long-running operation. required: - id - state - createdTime properties: id: type: string description: The unique identifier for this operation. state: type: string enum: - pending - running - succeeded - failed - cancelled description: The current state of the operation. metadata: type: object description: Service-specific metadata about the operation, such as progress information. additionalProperties: true result: type: object description: The result of the operation when state is 'succeeded'. additionalProperties: true errors: type: array description: Error details when state is 'failed'. items: type: object properties: code: type: string message: type: string- The response body schema must be an
Operationobject as described above. - The response body schema may contain an object property named
metadatato hold service-specific metadata associated with the operation, for example, progress information and common metadata such as create time. The service should define the contents of the metadata object in a separate schema, which should specifyadditionalProperties: trueto allow for future extensibility. - The
resultproperty must be a schema that defines the success response for the operation. For operations that typically return204 No Content(such as delete),resultshould be defined as an empty object schema. For operations that typically return a response body,resultshould contain a representation of the created or modified resource, or a summary of the operation’s outcome.
Changelog
Section titled “Changelog”- 2025-12-10: Initial creation, adapted from Google AIP-151 and aep.dev AEP-151.