Skip to main content

Integration developer: what you do and where

You build the external system that calls Lattice: a webshop or CRM connector, middleware, a script, or a partner feed that sends files. You look up contracts, make and test calls, trace what happened to them and subscribe to events. Lattice has no separate developer role. In a development or test environment, ask your administrator for Integration administrator: it opens every Lattice page on this list, including the Service test console, the OData entity metadata explorer and the Liquid template tester. In production, Integration read-only is enough to read service contracts and the business event catalog and to trace your calls (or build a custom role from the duties named below, see Security). The identity your integration calls with gets the role its calls need, which your administrator sets up (Connect an integration client). You will live in two pages: the Service metadata explorer for contracts and the Service call log for what happened to your calls.

Look up a contract​

I want to find the operation for a business process​

Where: Lattice scenarios, then System administration > Inquiries > Lattice > Services > Service metadata explorer.

  1. Open the scenarios list and pick the business outcome, for example Sales order to invoice. Each scenario walks through the operations in order, with their service group, service and a sample request.
  2. To browse instead, open the Service metadata explorer, type part of a name in the filter above the tree, and expand a service group and a service to see its operations.
  3. Select an operation. The Operation tab shows its Endpoint URL, Request contract class and Response contract class.
  4. Every Lattice call is POST https://<your-environment>/api/services/<service group>/<service>/<operation> with the request in _request. A batch operation takes its requests in _requests, and captureSpec and specFromPackageManifest take their parameters directly, for example { "_projectNamePattern": "", "_jobNamePattern": "" }.

Needs: any Lattice role: Integration administrator, Integration operator or Integration read-only (privilege View service metadata explorer). More: API reference: Endpoint pattern · Page reference: Service metadata explorer.

I want to review the request and response contract of a service operation​

Where: System administration > Inquiries > Lattice > Services > Service metadata explorer.

  1. Filter the tree and select the operation.
  2. Open Request schema for Sample request (JSON) and Sample request (XML), and Response schema for Sample response (JSON) and Sample response (XML). The JSON request sample is the whole body you send, with its _request wrapper (_requests for a batch operation). The values are placeholders that show each member's type.
  3. To save a sample as a file, click Download request or Download response in the JSON or XML group.
  4. Look the operation up in the endpoint payload specification for each member's meaning, whether it is required and a sample value from the USMF demo company. The members every request carries (RequestId, LegalEntityId, CorrelationId, UserContext) and the common response are described once in the API reference. Enum members in service responses are integers, for example Status 3 for Succeeded.
  5. If the operation is missing or out of date after an update, ask an Integration administrator to click Refresh metadata. Nothing schedules the refresh automatically.

Needs: any Lattice role. Refresh metadata needs Integration administrator (privilege Refresh service metadata). More: Endpoint payload specification · API reference: Common request fields · API reference: Common response format.

I want to review the data contract of an OData entity​

Where: System administration > Inquiries > Lattice > OData > OData entity metadata explorer, or OData metadata in the Lattice group of the standard Data entities page (Data management workspace > Data entities), which opens the explorer filtered to the selected entity.

  1. Type part of the entity name in the quick filter and select the row. Collection name is the name you use in the URL: https://<your-environment>/data/<collection name>.
  2. Details shows the Entity table, the Primary key and the Description.
  3. On Fields, Key and Mandatory together are the minimum an insert needs, and Allow edit tells you what an update may change. Data type, Extended data type and Enum type give each field's type.
  4. Methods lists the OData actions the entity exposes, with their parameters.
  5. For a Lattice entity, the entity reference also gives its Access (read-only or read/write), its Company (company-specific or shared across companies), its key, its fields and the privileges that grant it.
  6. If the entity is missing, ask an Integration administrator to run Refresh OData metadata: the list is a stored catalog, and nothing refreshes it automatically.

Needs: Integration administrator (duty OData entity metadata explorer access). The entity reference needs no access. More: Data entity reference · Data entities guide: Browsing the OData surface · Page reference: OData entity metadata explorer.

I want to download the OData metadata document for my client code​

Where: System administration > Inquiries > Lattice > OData > OData entity metadata explorer > OData service.

  1. Click OData service and choose Metadata document ($metadata). You get odata_metadata.xml, exactly what https://<your-environment>/data/$metadata returns (about 54 MB on a standard environment).
  2. For the list of entity sets, choose Service document (/data) instead. You get odata_service_document.xml.
  3. Neither download needs an access token or an app registration, and both work before the catalog has ever been refreshed. Right after an AOS restart, the first download can wait a minute or more while the environment builds its OData model.

Needs: Integration administrator (duty OData entity metadata explorer access). More: Data entities guide: Downloading the OData service and metadata documents.

I want to get a Postman collection or an OpenAPI specification​

Where: Service metadata explorer for service operations, OData entity metadata explorer for entities (both under System administration > Inquiries > Lattice).

  1. For service operations: on the Service metadata explorer, click Postman or OpenAPI in the Specifications group. You get postman_collection.json or openapi.json for the service operations in the explorer's catalog.
  2. For entities: on the OData entity metadata explorer, mark the entities your system calls, then choose Postman > Selected entities or OpenAPI > Selected entities. You get odata_postman_collection.json or odata_openapi.json. Prefer a selection: All entities produces files of about 55 MB.
  3. In Postman, fill the collection variables baseUrl, tenantId, clientId and clientSecret. The collections authenticate with the OAuth 2.0 client-credentials flow.
  4. Generate the files again after each update, once the catalogs have been refreshed.

Needs: any Lattice role for the service files; Integration administrator for the entity files. More: Page reference: Service metadata explorer · Data entities guide: Generating a Postman collection or an OpenAPI specification.

I want to find the business event for a business moment and its payload​

Where: System administration > Inquiries > Lattice business events > Business event catalog.

  1. Type part of the event name in the quick filter and select the event.
  2. Details shows the Description and the Contract class. Payload fields lists every JSON field the subscriber receives, with its Display label and Type.
  3. Click Download sample payload (in the Payload group). It saves <event>_sample.json, a document in the event's shape with a representative value for each field.
  4. Open the event's page in the business event reference for its trigger, its limits and an example, and read the rules every payload follows: company ids in lower case in the Lattice part, dates as \/Date(milliseconds)\/, enums as an integer plus a ...Name member, eventSequence and schemaVersion.

Needs: any Lattice role (privilege View business event catalog). More: Business event reference: What every payload contains · Page reference: Business event catalog.

Connect and make calls​

I want to authenticate and make a first call​

Where: your HTTP client, against https://<your-environment>.

  1. Get from your administrator the Directory (tenant) ID, the Application (client) ID and its secret, and confirm the app is registered on System administration > Setup > Microsoft Entra ID applications with a user that holds a Lattice role.
  2. Request a token with the OAuth 2.0 client-credentials flow from https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token, with the scope https://<your-environment>/.default. Send it as Authorization: Bearer <access_token> on every call.
  3. Make a read-only call first, for example POST /api/services/MGCLatticeAccountsReceivableServiceGroup/MGCLatticeSalesOrderPostingService/getSalesOrderStatus with { "_request": { "RequestId": "<new GUID>", "LegalEntityId": "USMF", "DocumentId": "<sales order>" } }. RequestId and an existing LegalEntityId are required on every posting and status query.
  4. Check Success and ErrorCode in the response. A status query is not written to the Service call log, so look for your first posting or preview there instead (see I want to trace one of my calls).

Needs: a Lattice role for the integration user that grants the operation; Integration read-only covers the status queries. More: Connect an integration client · API reference: Authentication · Trial guide: Day one.

Test without posting​

I want to try a posting without posting anything​

Where: your HTTP client: the same request with "PreviewMode": true.

  1. Check that the operation has a preview: postGeneralJournal, postIntercompanyJournal, confirmSalesOrder, postSalesPackingSlip and invoiceSalesOrder, and their batch variants. Every other operation whose request has a PreviewMode member refuses the flag with ErrorCode 10 (PreviewUnsupported) before it reads or writes anything. An operation without that member ignores the flag and runs for real: submitAsyncOperation queues the real posting, and applySpec and refreshMappings use their own ValidateOnly.
  2. Send the request with "PreviewMode": true.
  3. A clean preview returns Success true, PreviewApplied true and PreviewFidelity 1 (validation only). No document is written, no number sequence is used, no business event is raised, and the RequestId stays free for the real post. The call log row shows Preview Yes.
  4. Send the same request without the flag when you mean to post.

Needs: the operation's own privilege; there is no separate preview privilege. More: Posting preview.

I want to run an operation from inside Finance and Operations​

Where: System administration > Inquiries > Lattice > Services > Service test console.

  1. On Request, pick the Service name and Operation name from the lookups.
  2. Click Load sample to see the generated sample. Request JSON takes the request contract itself, so keep the object inside _request, remove the outer wrapper, and put in real values and a new RequestId.
  3. Tick Preview mode (validate / run-and-abort - no posting) for a run that commits nothing. It protects every operation whose request has a PreviewMode member (one without a preview refuses); an operation whose request has none, such as submitAsyncOperation, runs for real.
  4. Click Run and confirm the prompt. Read Status and Response JSON on Response.
  5. To keep the request, type a Request name and click Save request. Bring it back from Saved requests with Load selected.

Needs: Integration administrator (duty Execute integration service tests), plus the privilege of the operation you run. The console runs only Lattice operations, and real runs post live transactions. More: Integration guide: Testing a service operation safely · Page reference: Service test console.

When a call fails​

I want to find out why my call was refused​

Where: the response, then the Service call log.

  1. Check the HTTP status first. 401: no valid token (wrong scope, expired secret). 403: Finance and Operations refused the caller: the app is not on Microsoft Entra ID applications, or the user has no Lattice role that grants the operation. 404: the service group is not deployed, or a name in the URL is misspelled. 429: the environment is throttling you; back off and retry after Retry-After.
  2. On HTTP 200, read Success, ErrorCode, IsRetryable, Message and Errors. ErrorCode is an integer, for example 1 ValidationFailed, 2 DocumentNotFound, 3 InvalidStatus, 7 DuplicateRequest, 10 PreviewUnsupported or 14 AccessDenied. Route on ErrorCode, not on the message text.
  3. Resend unchanged, with the same RequestId, only when IsRetryable is true (for example 6 TransientRuntime, 8 RequestInProgress, 12 LicenseNotValid). Otherwise fix the request first.
  4. For more detail, open the call on the Service call log: Message is what you received and Error details holds the reasons.

Needs: nothing to read the response; the Service call log needs any Lattice role. More: API reference: error codes · API reference: Error response patterns · Connect an integration client.

I want to trace one of my calls​

Where: System administration > Inquiries > Lattice > Services > Service call log, or the LatticeServiceCallLogs entity.

  1. Open the Service call log and filter the Request ID column on the RequestId you sent. Replays, refusals and previews get a row too.
  2. Read Status, Error code, Message, Error details, Document ID and Duration (ms). User Context is what you sent in UserContext.
  3. To read the same rows from your system, call GET https://<your-environment>/data/LatticeServiceCallLogs?$filter=RequestId eq <guid> (a GUID is not quoted).
  4. For the idempotency claim behind a posting, filter Service idempotency log (or LatticeServiceIdempotencyLogs) on the same Request ID. An asynchronous operation is on the Async operations tab of Inbound message inquiry and in LatticeAsyncOperationTrackingRecords (filter on TrackingId).
  5. No row? A status query is never logged. Otherwise the operation's logging level may be Errors only or Off on System administration > Setup > Lattice > Service operation logging configuration, or the row is older than the retention window: 90 days for calls, 30 days for idempotency claims and asynchronous operations, by default.

Needs: any Lattice role (duty Integration service monitoring) for the pages and the three monitoring entities. More: Track documents and read data · Page reference: Service call log · Page reference: Service idempotency log.

I want to see what happened to a file I sent​

Where: System administration > Inquiries > Lattice > Integration operations > Inbound message inquiry.

  1. On Bundles, find your file by Source file name and note its Bundle ID. Download bundle payload returns the file as it was received.
  2. On Segments, the rows with that Bundle ID are the records of your file. Read State and, for a failure, Error message. Download segment payload returns one record as it was received.
  3. On Dead letter, a record that used up its attempts shows its Status, Error category and Attempts. An Integration administrator can correct and resubmit it on Dead-letter fix and resubmit.

Needs: any Lattice role (duty Inquire into inbound integration messages). More: Integration guide: Tracing an inbound message end to end · Page reference: Inbound message inquiry.

Make the integration robust​

I want to make my calls safe to retry​

Where: your client code; check the result on System administration > Inquiries > Lattice > Services > Service idempotency log.

  1. Give each business request its own GUID RequestId, store it with the request, and send the same RequestId on every retry of that request. A new RequestId is a new request.
  2. A repeat of a request that succeeded returns the first result (the same DocumentId and PostedDocumentId, message "Duplicate request detected...") and posts nothing. A request that failed releases its RequestId, so the retry runs again.
  3. Handle the idempotency codes: 8 RequestInProgress (the same RequestId is still running: retry later), 7 DuplicateRequest (the RequestId belongs to another operation: send a new one), 9 RequestNeedsReview (an earlier attempt stopped without a result: check whether it posted before you resubmit).
  4. To check a request, filter Service idempotency log on its Request ID. A claim still processing after an hour needs an Integration administrator.

Needs: only the operation's privilege; the log needs any Lattice role. More: Post a journal exactly once · API reference: Duplicate RequestId · Idempotency reconciliation runbook.

I want to send my own keys instead of D365 ids​

Where: System administration > Setup > Lattice > External systems, the cross-reference entities, and your requests.

  1. Have your external system registered once, for example SHOP with Active set: an Integration administrator adds it on External systems, or your integration creates it through the LatticeExternalSystems entity.
  2. Store your keys against the D365 records through the record kind's cross-reference entity, for example POST /data/LatticeSalesOrderCrossReferences with dataAreaId, SalesOrderNumber, ExternalSystem and ExternalKey.
  3. In a request, send ExternalSystem on the header and the key in the ...ExternalKey member next to the id it replaces, for example SalesOrderIdExternalKey. Status queries take DocumentIdExternalKey.
  4. A key that matches no record, or more than one, is refused with ValidationFailed before anything runs.
  5. Business events about a covered record carry your keys back in crossReferences.

Needs: sending keys needs only the operation's privilege. Registering a system and writing keys need Integration administrator (duty Maintain cross references); any Lattice role can read them. More: Use external keys · Cross-reference keys: Lattice services · Page reference: External systems.

I want to send many documents in one call​

Where: the operation's ...Batch variant.

  1. Append Batch to the operation name, for example confirmSalesOrderBatch, and send the requests in _requests, each with its own RequestId. The posting and action operations have a batch variant; the status queries, the asynchronous operations, the price inquiry and the data management configuration, mapping and database access operations do not.
  2. Read the envelope: Success is true only when every item succeeded, Status is 3 (all succeeded), 4 (all failed) or 6 (some failed), with TotalCount, SuccessCount and FailureCount.
  3. Match each entry of Results to your request by ItemIndex (one-based) or RequestId. Each item runs on its own: a failed item rolls nothing back for the others.
  4. To retry, resend the whole list unchanged. Items that succeeded replay their result and post nothing; items that failed run again.

Needs: the same privilege as the single operation. More: Batch and async operations.

I want to run a long posting in the background and collect the result​

Where: submitAsyncOperation and getAsyncOperationStatus on /api/services/MGCLatticeAsyncOperationServiceGroup/MGCLatticeAsyncOperationService/.

  1. Check that the operation can run asynchronously: the supported pairs are listed in the batch and async scenario and on System administration > Setup > Lattice > Async operation registry, where an Integration administrator can switch one off (a disabled pair is refused with 15 OperationDisabled).
  2. Call submitAsyncOperation with ServiceName, OperationName and, in RequestPayload, the target's own request as a JSON string with its own RequestId and LegalEntityId. The outer RequestId is the key of the submission.
  3. Keep the TrackingId from the answer (Status 1, Queued).
  4. Poll getAsyncOperationStatus with the TrackingId every few seconds, with back-off, until Status is 3 (Succeeded, with DocumentId and PostedDocumentId) or 4 (Failed, with ErrorCode, IsRetryable, Message and Errors).
  5. A failed operation is parked in the dead-letter queue on Integration operations console. Never give the payload a new RequestId to retry a posting: if the first attempt posted, that posts it again.

Needs: Integration operator or Integration administrator to submit, plus the privilege of the target operation (a few targets, such as fixed asset disposals and intercompany journals, are administrator only); any Lattice role to poll. More: Batch and async operations · Page reference: Async operation registry.

I want to read data back efficiently​

Where: the status query operations and the OData entities.

  1. For the state of one document, call its status query: getSalesOrderStatus, getPurchaseOrderStatus, getProductionOrderStatus, getJournalStatus or getWorkflowStatus. A query records no idempotency claim, so a new RequestId per call is fine.
  2. For lists and master data, read entities with $select and $top to keep each read small.
  3. For a company-specific entity, add cross-company=true and filter on dataAreaId, for example ?cross-company=true&$filter=dataAreaId eq 'usmf'. Without it, the read runs in the integration user's default company and returns nothing for another company. Shared entities take no dataAreaId; the Company line of each entity in the entity reference tells you which kind it is.
  4. Filter a GUID without quotes, and an enum with its qualified name, for example Status eq Microsoft.Dynamics.DataEntities.MGCLatticeServiceCallStatus'Failed'.
  5. To be told about changes instead of polling for them, subscribe to a business event.

Needs: any Lattice role for the status queries and the Lattice entities (duty Data Entities View). Standard Microsoft entities need standard Finance and Operations security. More: Track documents and read data · Data entity reference.

I want to subscribe my system to a business event​

Where: System administration > Setup > Business events > Business events catalog (the standard workspace).

  1. Find the event and its payload on the Lattice Business event catalog first (see I want to find the business event for a business moment and its payload).
  2. In the standard workspace, open Endpoints, click New, choose the endpoint type (for example Azure Service Bus or an HTTPS webhook) and enter its connection details.
  3. On Business event catalog, select the event, click Activate, and choose the endpoint. Choose a legal entity, or leave it blank to activate the event in every legal entity. Download schema exports the payload schema.
  4. Make the business moment happen and check that your endpoint receives the payload. A preview or a repeated RequestId posts nothing, so it raises no event.
  5. Make your consumer idempotent: de-duplicate on the business key and eventSequence, not on EventId, and ignore members you do not know.

Needs: standard Finance and Operations security for the Business events workspace, not a Lattice role. More: React to business events · Business events guide: Activating an event.

I want to know when a contract I use changes​

Where: the changelog, then the explorers after each update.

  1. Before an update, read the changelog for the release: it lists the changes that affect customers.
  2. After the update is deployed, an Integration administrator runs Refresh metadata on the Service metadata explorer, Refresh OData metadata on the OData entity metadata explorer and Refresh catalog on the Business event catalog. They run only when someone runs or schedules them.
  3. Download the samples, or the Postman and OpenAPI files, again and compare them with the ones you built against.
  4. For business events, check schemaVersion. Members are only added within a version, and a changed shape gets a higher schemaVersion; ignore members you do not know.

Needs: any Lattice role to download the service samples and files; the three refreshes need Integration administrator. More: Changelog · Business event reference: What every payload contains.

Send files instead of calls​

I want to write and test a Liquid template for my files​

Where: System administration > Inquiries > Lattice > File ingestion > Liquid template tester.

  1. On Input, paste your template into Liquid template and one record, not the whole file, into Data (JSON). The tester takes JSON; the pipeline converts an XML record to JSON before the template runs.
  2. Click Render and read Result on the Result tab: the rendered output, or the error.
  3. With the shipped service-invoke target, the template emits a routing envelope with service, operation, request and an optional requestKey, where request matches the operation's request contract. Put your record's stable id in requestKey, so a record that arrives again for the same company replays instead of posting twice. The operation must be one of the connection's Allowed service operations.
  4. Write a number in an unquoted position with {{ x | number }}, and loop over an element that may occur once or many times with as_array.
  5. To send your own keys instead of D365 ids, write $xref placeholders.

Needs: Integration administrator (privilege Maintain file ingestion). More: The Liquid transformer · File ingestion user guide: Liquid template tester · Cross-reference keys: File Ingestion.

I want to run a sample file through the pipeline without posting​

Where: System administration > Inquiries > Lattice > File ingestion > File ingestion simulator.

  1. On Input, set Connection ID to the connection your administrator set up for your files, and paste one record or a whole file into Raw payload.
  2. Click Run.
  3. On Results, read the steps (Sequence, Step, Succeeded, Message) from the top: parse, transform, preview. Produced contract is what the template produced for the first record, and Response is the preview's answer.
  4. Nothing is posted. The preview checks the envelope, the connection's Allowed service operations and the request, and calls the operation in preview mode only when it has a preview.
  5. To keep a file for later, store it on System administration > Setup > Lattice > File ingestion > Sample payloads and click Replay to run it through the simulator again.

Needs: Integration operator or Integration administrator (duty Use the file ingestion simulator). More: File ingestion user guide: File ingestion simulator · Page reference: File ingestion simulator · Page reference: Sample payloads.

I want to start from a ready-made intake bundle​

Where: Intake accelerators.

  1. Pick a bundle: vendor invoices (CSV over SFTP), sales orders (JSON from Azure Blob storage), ASN product receipts (XML over SFTP), customer payments (fixed width over SFTP) or opportunities (CSV to an OData entity).
  2. Open its folder: sample.<ext> is a sample file, mapping.json the field mapping, transform.liquid the Liquid transform, and README.md the verified target and the known gaps.
  3. Try transform.liquid on one record of the sample, as JSON, in the Liquid template tester.
  4. Give your administrator the values a bundle cannot carry (endpoint, credentials, journal names, legal entity). Each bundle lists them as activation parameters.
  5. The opportunity bundle targets an OData entity, which the file ingestion pipeline cannot write to: your own client writes those records.

Needs: no role to read the bundles; the Liquid template tester needs Integration administrator. More: Authoring intake accelerators · Activating a bundle.

I want to send or collect files for a recurring data job​

Where: your HTTP client, against the standard https://<your-environment>/api/connector/ endpoints and the LatticeRecurringDataJobs and LatticeRecurringJobMessages entities.

  1. Have your administrator authorize your app on the job: its application ID must be on System administration > Setup > Microsoft Entra ID applications and an enabled client application of the job (a LatticeRecurringDataJobClients row). Send the same bearer token as on any other call.
  2. Read the job's activity ID once: GET https://<your-environment>/data/LatticeRecurringDataJobs?$filter=Name eq '<job>'&$select=Name,ActivityId,Direction,State. Direction Inbound is an import job and Outbound an export job. The job processes files only while State is Active.
  3. To import, call POST https://<your-environment>/api/connector/enqueue/<ActivityId>?entity=<entity name> with the file as the request body, where <entity name> is the entity's name in the job's data project. Keep the message ID the call returns.
  4. Follow the message with GET https://<your-environment>/data/LatticeRecurringJobMessages?$filter=MessageId eq <message id> (a GUID is not quoted). Status moves from Enqueued to Processed, or ends in ProcessedWithErrors, PreProcessingError or PostProcessingError. A Processed message can still have failed rows: check ExecutionStatus, StagingErrorCount and TargetErrorCount. ExecutionId identifies the data management execution.
  5. To export, call GET https://<your-environment>/api/connector/dequeue/<ActivityId>, download the file the response points to, then call POST https://<your-environment>/api/connector/ack/<ActivityId> with the dequeue response as the body. The message's Status then becomes Acked.
  6. Lattice never resubmits a message: when rows fail, fix the data and enqueue the file again.

Needs: an Integration administrator to authorize your app on the job, and any Lattice role for your app's user to read the two Lattice entities. The /api/connector endpoints are standard Finance and Operations endpoints and follow standard security. More: Run recurring data jobs · Authorize a client application on a job · Find the rows a recurring import rejected · Data entity reference: Recurring data job message.