Skip to main content

Scenario: Send many requests at once, or run long work asynchronously

Goal. Cut the number of round trips when an integration has many documents to post, and keep long-running postings off the caller's HTTP connection. A ...Batch operation takes a list of requests in one call and answers with one result per item. submitAsyncOperation queues one long-running operation to the batch framework and answers at once with a tracking id, which the caller polls with getAsyncOperationStatus until the work is done.

When to use.

  • Batch operations when you have several requests for the same operation now (a day's sales orders to confirm, a set of journals to post) and each one completes in normal service time. Every item is processed independently, in the same call.
  • Async operations for the long-running operations the async registry accepts: fixed asset acquisitions, disposals, depreciation proposals and transactions after acquisition, the three currency revaluations, item cost calculation and pending price activation (new standard costs), general and intercompany journal postings and journal reversals, the posting of existing ledger, inventory, project, production and trade agreement journals (Post an existing journal), and budget entries and transfers. Use it when a posting may outlast your HTTP client's timeout, or when the caller should not wait.
  • For a single posting with retries, see Post a journal exactly-once.

Prerequisites​

  1. Security.

    • A ...Batch operation is granted by the same privilege as its single operation (for example MGCLatticeAccountsReceivableServiceMaintain for confirmSalesOrderBatch).
    • submitAsyncOperation needs MGCLatticeAsyncOperationServiceMaintain and the privilege that grants the target operation for a direct call (MGCLatticeGeneralLedgerServiceMaintain for postGeneralJournal; MGCLatticeFixedAssetsDisposalMaintain, MGCLatticeGeneralLedgerIntercompanyMaintain, MGCLatticeGeneralLedgerJournalReverseMaintain and MGCLatticeInventoryCostActivateMaintain, administrator role only, for disposals, intercompany journals, journal reversals and pending price activations). The operator role can submit every other async operation. Posting an existing journal asynchronously also needs the operations the journal's content requires, as for a direct call.
    • getAsyncOperationStatus needs MGCLatticeAsyncOperationServiceView (all three Lattice roles).

    See Security model.

  2. For async operations: a running batch server (System administration > Setup > Server configuration, an AOS marked as batch server). Each submission schedules its own one-time batch job. As the fallback, process automation must be initialized and the Lattice Async Operation Processing background process enabled (System administration > Setup > Process automations, Background processes): every minute it runs queued operations and recovers operations a stopped batch task left processing. Failed operations are retried by the Lattice dead-letter retry background process. Both run by themselves; there is nothing to schedule (Integration operations).

  3. The async pair is enabled on System administration > Setup > Lattice > Async operation registry. All nineteen shipped pairs are enabled unless an administrator switched one off.

  4. The client is connected (Connect an integration client).

Steps​

Send a batch​

  1. Build the list. Append Batch to the operation name and send the requests in _requests. Each item is the request the single operation takes, with its own RequestId. confirmSalesOrderBatch on MGCLatticeSalesOrderPostingService (MGCLatticeAccountsReceivableServiceGroup):

    POST https://<your-environment>/api/services/MGCLatticeAccountsReceivableServiceGroup/MGCLatticeSalesOrderPostingService/confirmSalesOrderBatch

    {
    "_requests": [
    { "RequestId": "a1b2c3d4-0001-4000-8000-000000000001", "LegalEntityId": "USMF",
    "SalesOrderId": "000698", "PostingDate": "2026-10-07" },
    { "RequestId": "a1b2c3d4-0001-4000-8000-000000000002", "LegalEntityId": "USMF",
    "SalesOrderId": "SO-MISSING", "PostingDate": "2026-10-07" }
    ]
    }

    The posting and action operations have a batch variant. The status queries, the async operations, the price inquiry, database access and Data management configuration have none, and setSalesPriceBatch answers with its own envelope.

  2. Read the envelope, then each item. The answer is one MGCLatticeBulkOperationResponseContract:

    {
    "Success": false,
    "Status": 6,
    "Message": "1 of 2 item(s) succeeded.",
    "TotalCount": 2,
    "SuccessCount": 1,
    "FailureCount": 1,
    "Results": [
    { "ItemIndex": 1, "RequestId": "a1b2c3d4-0001-4000-8000-000000000001", "Success": true, "Status": 3,
    "ErrorCode": 0, "IsRetryable": false, "DocumentId": "000698", "PostedDocumentId": "000698-1" },
    { "ItemIndex": 2, "RequestId": "a1b2c3d4-0001-4000-8000-000000000002", "Success": false, "Status": 4,
    "ErrorCode": 2, "IsRetryable": false, "Message": "Sales order confirmation failed due to validation or business rule constraints.",
    "Errors": ["Sales order SO-MISSING was not found."] }
    ]
    }

    Success is true only when every item succeeded. Status is 3 (Succeeded) when all items succeeded, 4 (Failed) when all failed, and 6 (PartialSuccess) when some did. ItemIndex is the item's one-based position in your list; match results to requests by it or by RequestId. Each item is processed on its own: a failed item rolls nothing back for the others.

  3. Retry only what needs it. A successful item's RequestId is recorded, and a failed item's is released. So you can resend the whole list unchanged: the items that succeeded replay their recorded result (same DocumentId and PostedDocumentId, message "Duplicate request detected...") and post nothing, and the items that failed run again. Fix the data first for an item whose IsRetryable is false.

Run an operation asynchronously​

  1. Submit it. submitAsyncOperation on MGCLatticeAsyncOperationService (MGCLatticeAsyncOperationServiceGroup) takes the target service and operation and, in RequestPayload, the target's own request (the object you would send as _request) serialized as a JSON string. The payload needs its own RequestId, the posting's idempotency key, and an existing LegalEntityId; the outer RequestId is the key of the submission.

    {
    "_request": {
    "RequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "LegalEntityId": "USMF",
    "ServiceName": "MGCLatticeGeneralLedgerJournalService",
    "OperationName": "postGeneralJournal",
    "RequestPayload": "{\"RequestId\":\"5143fdcf-9a1e-4b6c-8a0e-2f6d7c1b9e42\",\"LegalEntityId\":\"USMF\",\"JournalNameId\":\"GenJrn\",\"Description\":\"Month-end accruals\",\"PostingDate\":\"2026-10-07\",\"Lines\":[{\"MainAccountId\":\"110110\",\"OffsetMainAccountId\":\"110180\",\"AmountCurDebit\":1000.00,\"AmountCurCredit\":0,\"CurrencyCode\":\"USD\",\"TransDate\":\"2026-10-07\"}]}"
    }
    }

    It answers at once with Success true, a TrackingId and Status 1 (Queued). Sending the same submission again returns the first TrackingId and queues nothing.

  2. Poll for the result. getAsyncOperationStatus with the tracking id:

    { "_request": { "TrackingId": "e4f5a6b7-c8d9-4123-8567-89abcdef0123" } }

    Status moves from 1 (Queued) to 2 (Processing) to 3 (Succeeded) or 4 (Failed). Poll every few seconds with a back-off. An operation normally starts within seconds of the submit; allow a few minutes when the batch server is cold, for example just after a deployment.

  3. Use the result. On Succeeded, DocumentId and PostedDocumentId carry the target operation's result (for a general journal, the journal number) and Message its message. On Failed, ErrorCode, IsRetryable, Message and Errors carry the failure.

How to verify​

  • Batch: TotalCount equals the number of items you sent and SuccessCount plus FailureCount equals TotalCount. Each successful item's document is in Finance and Operations (for the example, the order's confirmation), and each item is a row in LatticeServiceCallLogs under its own RequestId.
  • Async: getAsyncOperationStatus returns Status 3 with the document id. The operation is also a row in LatticeAsyncOperationTrackingRecords (filter on TrackingId), with SubmittedBy, the timestamps and the result; the target call itself is in LatticeServiceCallLogs under the payload's RequestId. See Track documents and read data.

When it goes wrong​

Batch operations

What you seeMeaning and what to do
Success false, Status 4, "At least one request item is required.", no ResultsThe _requests list was missing or empty.
An item fails with ValidationFailed, "Request item N is empty..."That entry of the list was empty; the other items still ran.
An item replays the result of another item ("Duplicate request detected...")Two items carried the same RequestId: the second one replays the first and posts nothing. Give every item its own RequestId.
An item fails with DuplicateRequestThe item's RequestId was already used for a different operation. Send a new one.
An item fails with RequestInProgress, IsRetryable trueThe same RequestId is running in another call. Retry once it completes.
An item with PreviewMode trueGets its single operation's answer: a validation-only preview for the five operations that have one, PreviewUnsupported for every other.
Items fail with LicenseNotValidThe license was found not valid; resend unchanged once it is renewed.

Async operations. A refused submission returns Success false, Status 4, an all-zero TrackingId and the reason; nothing is queued.

ErrorCodeMeaning and what to do
ValidationFailedA missing member, a pair that is not supported ("The operation ... is not supported for async execution."), a payload that cannot be read as the operation's request, or a payload without RequestId or with an unknown LegalEntityId. Correct and resubmit.
OperationDisabledAn administrator disabled the pair in the async operation registry. Call the operation directly, or ask for it to be enabled.
AccessDenied"You do not have access to the service operation ..." The caller lacks the target operation's privilege.
DuplicateRequestThe submission's RequestId was used for another service operation.
LicenseNotValidSubmissions are refused while the license is not valid; IsRetryable is true.
  • Still Queued after several minutes: nothing picked the operation up. Check that the batch server is running and the Lattice Async Operation Processing background process is enabled (prerequisite 2).
  • Failed after it ran: the operation goes to the dead-letter queue. A failure the target operation reports as retryable (IsRetryable true, for example TransientRuntime) is retried automatically by the Lattice dead-letter retry background process; any other failure is parked there for a person. Open System administration > Inquiries > Lattice > Integration operations > Integration operations console to retry, hold, fix and resubmit, or discard it. A replay reuses the payload's RequestId, so it never posts twice. A submitter who lost access to the target operation, or a pair disabled after the submission, also fails the operation (AccessDenied, OperationDisabled).
  • Unknown tracking id: getAsyncOperationStatus returns Success false, Status 7 (NotFound) and ErrorCode DocumentNotFound. Tracking rows of finished operations are removed by the Lattice integration log cleanup background process after 30 days by default.
  • Never give the payload a new RequestId to retry a posting: if the first attempt posted, that posts it a second time. Resubmitting with a new submission RequestId but the same payload RequestId is safe: a posting that succeeded replays its recorded result, and one that failed runs again.

Reference​