Cross-reference keys
Lattice can store the keys other systems use for your D365 records: a CRM's account id for a customer, a marketplace's order number for a sales order, a legacy ERP's item code for a released product. These are cross-references. Integrations can then send the key they know instead of the D365 id, and Lattice's business events tell subscribers their own key back.
Concepts
- External system. A system whose keys you store, such as
SHOP,CRMorLEGACYERP. The list is shared by all legal entities. - Cross-reference. One external system's key for one D365 record. A record holds at most one key per external system, and can hold keys from several systems. Keys are stored per legal entity: the same external key can name a different record in each legal entity (for example the same CRM account mapped to a customer in two legal entities), and keys follow the security and company context of the records they describe.
- Record kind (target). The kind of record a key belongs to. Sales orders and return orders are separate kinds even though they share tables, and so are sales and purchase agreements.
- Key kind.
- Alternate key: identifies the record. Integrations can use it to find the record.
- Historical: a legacy value kept for reference. It is stored and shown, but never used to find a record.
- Enforce unique. When on, a key can belong to only one record of that kind, for that external system, in the legal entity. It cannot be turned on while duplicates exist: the save is refused and the duplicated keys are listed so you can clean them up first. Once it is on, the database enforces it as well (a unique index), so two integrations writing the same key at the same moment cannot both succeed.
Record kinds covered
| Module (settings page) | Record kinds |
|---|---|
| Accounts receivable parameters | Customer; sales order and line; return order and line; sales quotation and line; free text invoice and line; sales agreement and line |
| Procurement and sourcing parameters | Vendor; purchase order and line; purchase requisition and line; purchase agreement and line |
| Inventory and warehouse management parameters | Released product; product variant; batch; transfer order and line |
| Fixed assets parameters | Fixed asset |
| Project management and accounting parameters | Project; project contract |
| General ledger parameters | Journal (ledger journal) and journal line |
| Production control parameters | Production order; bill of materials and BOM version; route and route version |
Addresses and main accounts are not covered.
Setting it up
-
System administration > Setup > Lattice > External systems. Add each external system (id, description, Active). Keys can only be added or changed for an active system; an inactive system's keys are kept and still resolve. A system cannot be deleted while any legal entity has keys or settings for it. An integration can register its system itself through the
LatticeExternalSystemsOData entity (also enabled for Data management), which is shared across companies:POST /data/LatticeExternalSystems{ "ExternalSystemId": "CRM", "Description": "Customer relationship management", "Active": "Yes" } -
On each module's parameters page, open the Cross references tab and add a row per record kind and external system:
- Key kind: Alternate key or Historical.
- Visible on forms: show this system's keys in the record's Cross references page and FactBox.
- Editable on forms: allow adding, changing and deleting them on the Cross references page.
- Enforce unique: see Concepts.
A row for another module's record kind is refused with a message naming the right page.
A record kind and system without a settings row still accepts keys through the data entities and services. Such keys are alternate keys, are not unique, and are not shown on forms.
On the pages
Every covered page gets a Cross references button and a Cross references FactBox. Both appear only when at least one external system is set up as visible on forms for that record kind. Pages with lines also get a Line cross references button and FactBox for the selected line.
| Page | Button location |
|---|---|
| Customers | Customer tab > Set up |
| Sales order | Sales order tab > View; lines strip |
| Return order | Return order tab > Attachments; lines strip |
| Sales quotation | Sales quotation tab > View; lines strip |
| Free text invoice | Invoice tab > Related information; lines strip |
| Sales agreement | Sales agreement tab > Related information; lines strip |
| Vendors | Vendor tab > Set up |
| Purchase order | General tab > Related information; lines strip |
| Purchase requisition | Purchase requisition tab > Summary; lines strip |
| Purchase agreement | Purchase agreement tab > Related information; lines strip |
| Released product details | General tab, next to External codes |
| Released product variants | General tab, next to External codes |
| Batches | View group |
| Transfer orders | Transfer order tab > View; lines strip |
| Fixed assets | Fixed asset tab > Maintain |
| Projects, Project contracts | Project / Project contract tab > Set up |
| Journals (all journal list pages) | Main button strip |
| General journal lines | Lines strip (line keys) |
| All production orders, production order details | Manage tab > Order details |
| Bills of materials | Maintain tab; Versions strip ("Version cross references") |
| Released product BOM versions | Maintain BOM version group |
| All routes | Route tab > Maintain; Versions strip ("Version cross references") |
| Released product route versions | Maintain route version group |
The Cross references page shows the record's keys per external system, with the key kind. Users with the module's View privilege see it read-only; Maintain allows editing, for external systems set up as editable on forms.
Journal line keys are offered on the general journal lines page only; other journal line pages are candidates for a later release.
Data entities
Every record kind has its own entity, keyed by the record's business key plus ExternalSystem, with
ExternalKey as the value. All are enabled for Data management and OData.
| Record kind | OData collection | Entity key (+ ExternalSystem) |
|---|---|---|
| Customer | LatticeCustomerCrossReferences | CustomerAccount |
| Vendor | LatticeVendorCrossReferences | VendorAccountNumber |
| Released product | LatticeReleasedProductCrossReferences | ItemNumber |
| Product variant | LatticeProductVariantCrossReferences | ItemNumber, ProductConfigurationId, ProductSizeId, ProductColorId, ProductStyleId, ProductVersionId |
| Batch | LatticeBatchCrossReferences | ItemNumber, BatchNumber |
| Fixed asset | LatticeFixedAssetCrossReferences | FixedAssetNumber |
| Project | LatticeProjectCrossReferences | ProjectId |
| Project contract | LatticeProjectContractCrossReferences | ProjectContractId |
| Sales order / line | LatticeSalesOrderCrossReferences / LatticeSalesOrderLineCrossReferences | SalesOrderNumber / InventoryLotId (the line's lot id) |
| Return order / line | LatticeReturnOrderCrossReferences / LatticeReturnOrderLineCrossReferences | ReturnOrderNumber / InventoryLotId (the line's lot id) |
| Sales quotation / line | LatticeSalesQuotationCrossReferences / LatticeSalesQuotationLineCrossReferences | SalesQuotationNumber / InventoryLotId (the line's lot id) |
| Free text invoice / line | LatticeFreeTextInvoiceCrossReferences / LatticeFreeTextInvoiceLineCrossReferences | InvoiceIdentifier (the invoice record id) / InvoiceIdentifier + LineNumber |
| Sales agreement / line | LatticeSalesAgreementCrossReferences / LatticeSalesAgreementLineCrossReferences | SalesAgreementId (+ LineNumber) |
| Purchase order / line | LatticePurchaseOrderCrossReferences / LatticePurchaseOrderLineCrossReferences | PurchaseOrderNumber (+ LineNumber) |
| Purchase requisition / line | LatticePurchaseRequisitionCrossReferences / LatticePurchaseRequisitionLineCrossReferences | RequisitionNumber (+ RequisitionLineNumber) |
| Purchase agreement / line | LatticePurchaseAgreementCrossReferences / LatticePurchaseAgreementLineCrossReferences | PurchaseAgreementId (+ LineNumber) |
| Transfer order / line | LatticeTransferOrderCrossReferences / LatticeTransferOrderLineCrossReferences | TransferOrderNumber (+ LineNumber) |
| Production order | LatticeProductionOrderCrossReferences | ProductionOrderNumber |
| BOM | LatticeBOMCrossReferences | BOMId |
| BOM version | LatticeBOMVersionCrossReferences | ManufacturedItemNumber, BOMId, SequenceId |
| Route | LatticeRouteCrossReferences | RouteId |
| Route version | LatticeRouteVersionCrossReferences | Microsoft's route version key (item, route, site, product dimensions, IsActive, ValidFromDate, ValidFromQuantity) |
| Journal / line | LatticeLedgerJournalCrossReferences / LatticeLedgerJournalLineCrossReferences | JournalBatchNumber (+ LineNumber) |
Rules:
- The entities always maintain keys, whatever the form settings say.
- An empty
ExternalKeyclears the key, so a Data management file or an OData PATCH can blank it. OData DELETE also removes it. - A business key that names no record (or a record of the other kind, such as a sales order number sent to the return order entity) is refused.
- A route version key matching two versions is refused; maintain such keys on the Cross references page.
- Product variants leave the dimensions they do not use empty.
Using keys in integrations
Only alternate keys resolve. A key that matches no record, or more than one, is an error, never a silent blank. When a request sends both a D365 id and a key, they must name the same record.
Lattice services
Request contracts that take a D365 id also accept an ExternalSystem member (on the request header) and an
<Id>ExternalKey member next to each id, for example CustAccountExternalKey, SalesOrderIdExternalKey, line
ItemIdExternalKey, line LineNumExternalKey. Line keys use the header's ExternalSystem. Keys resolve in the
request's legal entity, before the operation's own lookups; a key that does not resolve fails the request as
ValidationFailed. Batch operations accept the same members per item.
| Service | Key members |
|---|---|
| Sales order posting (confirm, packing slip, invoice, packing slip cancellation) | SalesOrderIdExternalKey |
| Sales order capture (create) | CustAccountExternalKey; line ItemIdExternalKey |
| Price inquiry | CustAccountExternalKey, ItemIdExternalKey |
| Transfer order posting (ship, receive) | TransferOrderIdExternalKey; line ItemIdExternalKey, LineNumExternalKey (a line key also fills in the line's item) |
| Purchase order posting (confirm, receipt, invoice, product receipt cancellation, prepayment invoice) | PurchaseOrderIdExternalKey |
| Return orders | SalesOrderIdExternalKey, PurchaseOrderIdExternalKey, CustAccountExternalKey, VendAccountExternalKey; line ItemIdExternalKey |
| Purchase requisitions | PurchReqIdExternalKey |
| Vendor invoice journal | line VendAccountExternalKey |
| Pending vendor invoices | VendorAccountExternalKey (with InvoiceNumber, in place of HeaderReference) |
| Production order posting | ProdIdExternalKey; pick list line ItemIdExternalKey |
| Free text invoice | InvoiceAccountExternalKey (post); InvoiceRecIdExternalKey (cancel) |
| Inventory journals | line ItemIdExternalKey; BOM journal line BOMIdExternalKey; ownership change line VendAccountExternalKey |
| Fixed assets | line AssetIdExternalKey (acquisition); AssetIdExternalKey (disposal) |
| Payment journals, settlements, payment reversals | AccountNumExternalKey (customer or vendor, by operation); prepayment line SalesOrderIdExternalKey or PurchaseOrderIdExternalKey |
| General ledger journal reversal | JournalNumExternalKey |
| Project invoice, project journals | ProjIdExternalKey; line ProjIdExternalKey, ItemIdExternalKey |
| Sales trade agreement | AccountRelationExternalKey (only with account code Table), ItemRelationExternalKey (only with item code Table) |
| Status queries (sales, purchase, production, journal, workflow) | DocumentIdExternalKey (workflow status: a purchase requisition's key) |
Not covered: the Lines of sales and purchase order posting requests (they take D365 line numbers and item ids),
return order line numbers, route card lines, depreciation proposals, workflow submission, async operations, database access and DMF
configuration.
Existing Lattice data entities
These writable entities accept ExternalSystem plus a key field in place of a lookup value. The key fields are
unmapped, so they read back empty.
- Sales order line and purchase order line:
SalesOrderNumberExternalKey/PurchaseOrderNumberExternalKey,ItemNumberExternalKey. - Free text invoice template line:
ProjectIdExternalKey. - Payment request:
AccountNumberExternalKey(customer or vendor by AccountType). - Vendor contact person:
VendorAccountNumberExternalKey. - Document attachment entities: the parent's key (
CustomerAccountExternalKey,VendorAccountNumberExternalKey,SalesOrderNumberExternalKey,PurchaseOrderNumberExternalKey,TransferOrderNumberExternalKey,ProductionOrderNumberExternalKey,ProjectIdExternalKey,InvoiceIdExternalKeyfor a posted free text invoice), and line keys on the purchase order line and transfer order line attachments.
Lookups that are part of an entity's primary key (contact info, summary update parameters, item group and model group assignments, sales order line charges) are not supported: Data management matches rows by key before any entity logic runs.
File Ingestion
A connection's Liquid template can write a cross-reference placeholder wherever the request needs a D365 id:
"CustAccount": { "$xref": { "target": "Customer", "system": "SHOP", "key": "{{ order.customer_id }}" } }
targetis a record kind name (Customer, Vendor, ReleasedProduct, SalesOrder, SalesOrderLine, ...).systemis the external system id,keythe external key.- The optional
fieldnames the record field to return. The default is the record's id: the account, item, order or journal number; the retail variant number for product variants; the line number for lines; the record id for free text invoices and BOM and route versions.
Placeholders are resolved after the template renders and before the request is dispatched, in the pipeline and in the File Ingestion simulator. The stored transformed content shows the resolved ids. A placeholder that does not resolve fails the record like any other data error.
Business events
Events about a covered record carry a crossReferences array of { "externalKey": ..., "externalSystem": ... },
ordered by external system, including historical keys; it is [] when the record has none. Events raised from a
journal (confirmation, packing slip, invoice, credit note, quotation confirmation) report the keys of the document
they are about. The events: customer created, updated and credit hold changed; vendor created, updated and hold
status changed; released product created; fixed asset acquisition and disposal posted; sales order canceled,
confirmed, invoice posted, packing slip posted and line changed; sales return order created, return order received,
return credit note posted; purchase return order created; transfer order shipped and received; sales quotation
confirmed; production order started, ended, estimated, scheduled, reported as finished, pick list posted, route card
posted; free text invoice posted; sales and purchase agreement confirmed; purchase requisition approved; BOM
version approved; general journal posted; vendor payment journal posted (the keys of the journal line).
Security
| Privilege | Grants |
|---|---|
| View / Maintain external systems | The External systems page and the LatticeExternalSystems entity (read / full access) |
View / Maintain <module> cross references (7 modules) | The module's Cross references page and the FactBox, and the module's cross-reference entities |
Duties: Inquire into cross references (all View privileges) is in the Lattice integration operator and read-only roles; Maintain cross references (all Maintain privileges) is in the Lattice integration administrator role. Assign the per-module privileges directly to give, for example, an AR clerk customer keys without general ledger keys.
Behavior to know
- Keys are removed when their record is deleted. Agreement headers and lines are handled through their
delete()(they are deleted withdoDeleteor soft-deleted, so no Deleted event fires). A set-based delete that skips events can leave orphan keys. The removal costs nothing in a legal entity that holds no key of that kind of record: whether any key exists is checked once and cached. - Batches are the exception: their keys are not removed with the batch, so that the standard set-based deletion of batches stays set-based. A deleted batch's keys remain as rows that point at no record; batch record IDs are never reused, so they never attach to another batch.
- Purchase requisitions and agreements are shared across legal entities. Their keys are kept in one owning legal
entity: a sales agreement's in its selling legal entity, a purchase agreement's in its buying legal entity, and a
purchase requisition's (and its lines') in the requisition's default buying legal entity. The Cross references page
opened in another legal entity shows them read-only, the data entities refuse a row written with another
dataAreaId, and the business events report the keys of the owning legal entity. - Soft-deleted purchase lines and agreement rows keep their keys until the row is really removed; the purchase order line, purchase agreement and sales agreement entities do not return the keys of soft-deleted rows.
- Sales order, return order and sales quotation lines are addressed by their lot id (
InventoryLotId): the order number and line number are returned on these entities but are not unique (lines created by Commerce statement posting all carry line number 0). - Purchase order keys cover every purchase order type, including returns.
- The route version entity key includes the active flag and dates (as Microsoft's entity does), so activating a version changes its entity key; the stored key itself is unaffected.
For developers
- Tables:
MGCLatticeExternalSystem(global),MGCLatticeCrossReferenceSetupandMGCLatticeCrossReference(per legal entity; a record of a shared table in its owning legal entity,MGCLatticeCrossReferenceTargetMap::owningCompany).UniquenessDiscriminator(0 when keys must be unique, otherwise the record id) completes the unique indexExternalKeyIdx(Target, ExternalSystemId, ExternalKey, UniquenessDiscriminator). Keys are stored by table id and record id (the root table of a table hierarchy), so renaming a record's business id keeps its keys. MGCLatticeCrossReferenceManager:setExternalKey,externalKey,keysForRecord,resolve,resolveRecord,deleteForRecord.MGCLatticeCrossReferenceResolver:coalesceId,coalesceLineNumber,resolveId,resolveValue.MGCLatticeCrossReferenceTargetMap: record kind to table, module and menu item, and record to record kind.MGCLatticeCrossReferenceJsonResolver: the File Ingestion$xrefstep.MGCLatticeCrossReferenceEventHelper::listFor: the events'crossReferenceslist.