Skip to main content

Scenario: Run a fixed asset from acquisition to disposal

Goal. Your asset register, procurement or lease system drives a fixed asset through its life in Dynamics 365: it posts the acquisition of an asset book, runs the depreciation proposal for the period, posts the adjustments, depreciation, revaluations and write-downs it decides, moves the asset to another department or location, splits off part of it, reverses a posting made in error, and finally posts the disposal of the asset by sale or by scrap, then reads the transactions back to confirm them.

When to use. Capitalizing assets bought outside D365, period-end depreciation driven by an external close calendar, impairments and revaluations decided in the register, reorganizations that move assets between departments or sites, and retirements decided outside D365. For plain ledger entries use General and intercompany journals; for a fixed asset journal that was entered or imported in D365 and only needs posting, see Post an existing journal; for the retry-safe calling pattern, see Post a journal exactly-once.

Prerequisites​

  1. Security.

    • postAcquisition, runDepreciationProposal, postAssetTransaction, transferAsset and splitAsset: privilege MGCLatticeFixedAssetsServiceMaintain, in duty MGCLatticeIntegrationServiceOperationsDuty (operator and administrator roles).
    • postDisposal: privilege MGCLatticeFixedAssetsDisposalMaintain, in the high-risk duty MGCLatticeIntegrationServiceHighRiskDuty, held only by MGCLatticeIntegrationAdministratorRole.
    • reverseAssetTransaction: privilege MGCLatticeFixedAssetsReverseMaintain ("Fixed assets - reverse transactions (high-risk)"), in the same high-risk duty. Posting a transaction does not grant reversing it.

    A call without the privilege is refused by D365 with HTTP 403.

  2. Fixed asset setup in the legal entity.

    • A ledger journal name of type Fixed assets with a voucher number sequence (General ledger > Journal setup > Journal names), on the posting layer of the books you post. USMF: FACur (current layer).
    • A fixed asset group (Fixed assets > Setup > Fixed asset groups), a book (Fixed assets > Setup > Books) and a posting profile with the accounts of every transaction type you post (acquisition, depreciation, adjustments, revaluation, write-up and write-down, extraordinary and bonus depreciation) and the sale and scrap setup on its Disposal tab (Fixed assets > Setup > Fixed asset posting profiles). USMF: group COMP, book 200_SLLR (current layer, depreciation profile 200%), posting profile ALL, which has accounts for every type except bonus depreciation.
    • An offset main account that allows manual entry for the acquisition cost and the sale proceeds. USMF: 110110 Bank Account - USD.
    • An open ledger period for the dates you post.
    • Transfers: the transfer number sequence (Fixed assets > Setup > Fixed assets parameters, Number sequences), and the dimension values and locations you move to (USMF: department 023, location PROD).
    • Splits into a new asset: automatic numbering on the asset group, since the split creates the receiving asset.
    • Reversals: the reversal voucher and trace number sequences in the general ledger parameters (General ledger > Ledger setup > General ledger parameters, Number sequences; USMF has them).
  3. The asset and its book exist. Lattice posts transactions for an asset; it does not create the asset (except the receiving asset of a split). Create it on Fixed assets > Fixed assets > Fixed assets, or with the standard OData entities (step 1).

  4. Lattice. A valid license (a never-registered environment is allowed through; an adverse verdict refuses posting with LicenseNotValid). If your system knows the asset by its own key, register it as a cross-reference and send AssetIdExternalKey with ExternalSystem instead of AssetId (on every operation here; a split also takes ToAssetIdExternalKey); see Cross-reference keys.

Steps​

The operations are on MGCLatticeFixedAssetService in service group MGCLatticeFixedAssetsServiceGroup. Send a POST with an OAuth 2.0 bearer token and the request in _request (see Trial and day-one guide).

  1. Create the asset and attach its book (if it does not exist yet). Create the asset in its group with the standard FixedAssetsV2 entity, then attach the book with FixedAssetBooksV2:

    POST https://<your-environment>/data/FixedAssetsV2
    { "FixedAssetGroupId": "COMP", "Name": "Engineering workstation", "dataAreaId": "USMF" }

    The response carries the new FixedAssetNumber (from the group's number sequence). Then:

    POST https://<your-environment>/data/FixedAssetBooksV2
    {
    "FixedAssetNumber": "COMP-000001",
    "BookId": "200_SLLR",
    "PostingProfileId": "ALL",
    "DepreciationProfileId": "200%",
    "ServiceLife": 5,
    "dataAreaId": "USMF"
    }
  2. Post the acquisition. postAcquisition creates a fixed asset journal with one acquisition line per request line and posts it:

    POST https://<your-environment>/api/services/MGCLatticeFixedAssetsServiceGroup/MGCLatticeFixedAssetService/postAcquisition
    {
    "_request": {
    "RequestId": "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b",
    "LegalEntityId": "USMF",
    "UserContext": "asset-register",
    "JournalNameId": "FACur",
    "Description": "Workstation acquisition",
    "PostingDate": "2026-10-15",
    "Lines": [
    {
    "AssetId": "COMP-000001",
    "AssetBookId": "200_SLLR",
    "AcquisitionAmount": 15000.00,
    "CurrencyCode": "USD",
    "OffsetMainAccountId": "110110",
    "Description": "Workstation"
    }
    ]
    }
    }

    Every line needs AssetId, AssetBookId and a non-zero AcquisitionAmount; CurrencyCode defaults to the accounting currency. The answer: Success true, DocumentId = PostedDocumentId = the journal number, message "Fixed asset acquisition journal ... posted." The book is now acquired. Each line posts to the book it names only: the book's derived books do not receive the acquisition, so send a line for every book you acquire.

  3. Run the depreciation proposal. runDepreciationProposal runs the standard depreciation proposal (the fixed asset journal's Proposals > Depreciation proposal) into a new fixed asset journal, one line per asset book with depreciation due through DepreciationDate:

    POST https://<your-environment>/api/services/MGCLatticeFixedAssetsServiceGroup/MGCLatticeFixedAssetService/runDepreciationProposal
    {
    "_request": {
    "RequestId": "7a8b9c0d-1e2f-4a3b-8c4d-5e6f7a8b9c0d",
    "LegalEntityId": "USMF",
    "UserContext": "asset-register",
    "JournalNameId": "FACur",
    "AssetBookId": "200_SLLR",
    "DepreciationDate": "2026-10-31"
    }
    }

    The proposal covers every asset of the book (every book when AssetBookId is empty), not only yours, and the journal is not posted. DocumentId = PostedDocumentId = the proposal journal number. The message gives the count ("Depreciation proposal journal ... was created through ... with N proposed line(s). The journal is not posted.") or says nothing was due ("... has no lines: no fixed asset book in the selection has depreciation due."); an asset acquired in the current period often has nothing due yet. Review and post the journal in D365: Fixed assets > Journal entries > Fixed assets journal, select the journal number, open Lines, check the proposed amounts and click Post; or post it with postLedgerJournal (Post an existing journal). An empty proposal journal can be deleted there.

  4. Post depreciation, adjustments and revaluations. postAssetTransaction posts the transactions after acquisition that your register decides, in a new fixed asset journal, as the fixed asset journal page posts them:

    POST https://<your-environment>/api/services/MGCLatticeFixedAssetsServiceGroup/MGCLatticeFixedAssetService/postAssetTransaction
    {
    "_request": {
    "RequestId": "2d4f6a8c-0e1b-4c3d-9e5f-7a9b1c3d5e7f",
    "LegalEntityId": "USMF",
    "UserContext": "asset-register",
    "JournalNameId": "FACur",
    "Description": "October impairment",
    "PostingDate": "2026-10-31",
    "Lines": [
    { "AssetId": "COMP-000001", "AssetBookId": "200_SLLR", "TransactionType": "Depreciation", "CreditAmount": 250.00 },
    { "AssetId": "COMP-000001", "AssetBookId": "200_SLLR", "TransactionType": "WriteDownAdj", "CreditAmount": 500.00,
    "Dimensions": [ { "DimensionName": "Department", "DimensionValue": "023" } ] }
    ]
    }
    }
    TransactionTypePosts
    AcquisitionAdjAn acquisition adjustment
    Depreciation, DepreciationAdjDepreciation, a depreciation adjustment
    ExtraordinaryDepreciation, BonusDepreciationExtraordinary or bonus depreciation
    RevaluationA revaluation, where the book allows it
    WriteUpAdj, WriteDownAdjA write-up or write-down adjustment
    • The type names are not case-sensitive. Acquisitions are posted with postAcquisition (step 2), disposals with postDisposal (step 8); any other type is refused.
    • Each line has exactly one amount, greater than zero, in the accounting currency: DebitAmount increases the book's value, CreditAmount decreases it (a depreciation or a write-down is a credit).
    • The book's posting profile gives the account and the offset account of the type unless the line sends OffsetMainAccountId; the line takes the book's financial dimensions, and Dimensions replaces the ones you name. TransactionDate defaults to PostingDate (today). ReasonCode and ReasonComment carry a financial reason, which the fixed asset parameters can require per type; ConsumptionQuantity is the consumption of a depreciation line on a book that depreciates by consumption.
    • The depreciation types need a book that depreciates. The derived books of a line's book take the transaction as the fixed asset journal passes it to them, except a derived book that is not acquired.
    • A line whose type has no account (or no offset account) in the book's posting profile is refused with ConfigurationMissing before any journal is created. USMF's profile ALL has no bonus depreciation accounts, so BonusDepreciation is refused there until you add them.

    The answer: DocumentId is the posted journal, PostedDocumentId the voucher of its first line, and the message lists every voucher: "Fixed asset journal ... posted with 2 line(s), voucher(s) ...". A journal that does not post is deleted again.

  5. Move the asset to another department or location. transferAsset runs the standard asset transfer (the fixed asset page's Transfer asset) and posts what it creates:

    {
    "_request": {
    "RequestId": "4f6b8d0f-2a3c-4e5d-8f7a-9b1d3f5a7c9e",
    "LegalEntityId": "USMF",
    "UserContext": "asset-register",
    "AssetId": "COMP-000001",
    "Dimensions": [ { "DimensionName": "Department", "DimensionValue": "023" } ],
    "LocationId": "PROD",
    "TransferDate": "2026-11-01",
    "Comment": "Moved to production engineering"
    }
    }

    Send Dimensions, LocationId or both. For each book (only AssetBookId when you send it; otherwise every open or closed book of the asset that has a posting layer), the transfer posts a general ledger voucher that moves the book's balance from its current dimensions to the new ones, writes an asset transfer transaction and the transfer history, and gives the book the new dimensions. The dimensions you send replace the same dimensions of each book; the others keep their values, and a book that already has the result is left as it is. LocationId is the asset's location. TransferDate defaults to today and must be a date of the fiscal calendar. DocumentId is the asset, PostedDocumentId the voucher of the first transferred book (empty when only the location changes).

  6. Split off part of the asset. splitAsset runs the standard asset split (the book's Split asset) and posts the split journal it creates, in one transaction:

    {
    "_request": {
    "RequestId": "6a8c0e2a-4b5d-4f6e-9a8b-0c2e4a6c8e0a",
    "LegalEntityId": "USMF",
    "UserContext": "asset-register",
    "AssetId": "COMP-000001",
    "AssetBookId": "200_SLLR",
    "Percent": 40,
    "JournalNameId": "FACur",
    "SplitDate": "2026-11-15"
    }
    }
    • Send Percent (greater than 0, at most 100) or Quantity (units, at most the asset's quantity), not both. A quantity is turned into the share it is of the asset's quantity, and the units move to the receiving asset; a percentage moves values only.
    • The share of the book's acquisition, depreciation and other values moves to the receiving asset's book (ToAssetBookId, default the same book). Without ToAssetId the receiving asset is created as a copy of the asset (same group and details, every book copied, none acquired); with it, that existing asset receives the split. Derived books the split asset has not acquired are left out.
    • DocumentId is the asset that was split, PostedDocumentId the asset that received it, and the message names the posted split journal: "40 percent of book 200_SLLR of fixed asset COMP-000001 was split into fixed asset COMP-000002; split journal ... posted." Nothing is kept when the split journal does not post.
  7. Reverse a posting made in error. reverseAssetTransaction reverses a posted fixed asset voucher of a book with the standard reversal (the fixed asset transactions page's Reverse transaction): the general ledger voucher and every asset transaction of the voucher are reversed, and the book is updated as the standard reversal updates it:

    {
    "_request": {
    "RequestId": "8c0e2a4c-6d7f-4a8b-9c0d-2e4a6c8e0a2c",
    "LegalEntityId": "USMF",
    "UserContext": "asset-register",
    "AssetId": "COMP-000001",
    "AssetBookId": "200_SLLR",
    "Voucher": "<voucher from step 4>",
    "ReversalDate": "2026-11-02",
    "ReasonCode": "ERROR",
    "ReasonComment": "Write-down posted to the wrong asset"
    }
    }

    ReversalDate defaults to today and cannot be before the transaction; TransactionDate is needed only when the voucher has transactions of the book on several dates. DocumentId is the reversed voucher, PostedDocumentId the reversal voucher. A voucher posted with a vendor or customer transaction is reversed in accounts payable or receivable instead.

  8. Post the disposal. postDisposal creates and posts a fixed asset journal with one disposal line for the asset book. For a sale, set IsSale to true, the proceeds in SaleAmount, and the account that receives them in OffsetMainAccountId (without it the sale voucher cannot balance and the post fails):

    POST https://<your-environment>/api/services/MGCLatticeFixedAssetsServiceGroup/MGCLatticeFixedAssetService/postDisposal
    {
    "_request": {
    "RequestId": "9c0d1e2f-3a4b-4c5d-8e6f-7a8b9c0d1e2f",
    "LegalEntityId": "USMF",
    "UserContext": "asset-register",
    "JournalNameId": "FACur",
    "AssetId": "COMP-000001",
    "AssetBookId": "200_SLLR",
    "IsSale": true,
    "SaleAmount": 5000.00,
    "OffsetMainAccountId": "110110",
    "CurrencyCode": "USD",
    "DisposalDate": "2026-12-31"
    }
    }

    For a scrap, send "IsSale": false and leave out SaleAmount and OffsetMainAccountId. Always send IsSale: a request without it is a scrap. The disposal posts to the book you name only, not to its derived books. The answer: DocumentId = PostedDocumentId = the disposal journal number, message "Fixed asset ... disposal posted in journal ...".

  9. Read the transactions back. Read the Lattice entity LatticeFixedAssetTransactions for the asset and book:

    GET https://<your-environment>/data/LatticeFixedAssetTransactions?$filter=AssetId eq 'COMP-000001' and BookId eq '200_SLLR' and dataAreaId eq 'usmf'&cross-company=true&$select=AssetTransType,TransactionDate,Voucher,AccountingCurrencyAmount

    A posted sale has a row with AssetTransType DisposalSale (a scrap: DisposalScrap) on the disposal date; its Voucher is the disposal voucher. The same read shows the Acquisition row from step 2, the Depreciation rows once you posted the proposal journal, a row per transaction of step 4 under its voucher (credits negative), the AssetTransfer row of step 5, the split's acquisition adjustment, and for a reversal a row with the opposite amount under the reversal voucher.

Bulk variants postAcquisitionBatch, runDepreciationProposalBatch, postAssetTransactionBatch, transferAssetBatch, splitAssetBatch, reverseAssetTransactionBatch and postDisposalBatch take a _requests list. postAcquisition, runDepreciationProposal, postAssetTransaction and postDisposal can also be queued with submitAsyncOperation (see API reference, sections 19 and 21). None of the operations has a preview.

How to verify​

  • Each response: Success true, Status 3. Acquisition, proposal and disposal: DocumentId = PostedDocumentId = the journal number. Transactions: the journal and its first voucher. Transfer: the asset and the first transfer voucher. Split: the split asset and the receiving asset. Reversal: the reversed and the reversal voucher.
  • LatticeFixedAssetTransactions shows Acquisition, then Depreciation (after you post the proposal), the transactions you posted, then DisposalSale or DisposalScrap for the asset book.
  • A transfer: FixedAssetBooksV2 shows the book's new DimensionDisplayValue, and FixedAssetsV2 the asset's AssetLocationId. A split: the receiving asset exists in FixedAssetsV2, with its book acquired.
  • The proposal journal's lines: read the standard AssetJournalLines entity filtered on JournalBatchNumber (the proposal journal number) and dataAreaId, with cross-company=true; their count matches the message.
  • In D365: Fixed assets > Journal entries > Fixed assets journal lists the posted journals and the unposted proposal; open the asset on Fixed assets > Fixed assets > Fixed assets and its Books to see the book's status and transactions, and Transfer history for the transfers. A reversed transaction shows as reversed on the book's transactions.
  • If you subscribe to business events, Fixed asset acquisition posted and Fixed asset disposal posted fire for the acquisition and disposal transactions.

When it goes wrong​

A failed request answers Success false, Status 4, an ErrorCode and a generic Message; the reasons are in Errors.

ErrorCodeTypical cause (text in Errors)What to do
ValidationFailed (1)No RequestId or unknown LegalEntityId; "JournalNameId is required."; "Journal name ... was not found."; "At least one acquisition line is required."; "Request line N is empty."; "Line N: AssetBookId is required." (or AcquisitionAmount); "Fixed asset ... was not found."; "AssetId is required."; "AssetBookId is required."; proposal: "Journal name ... is a ... journal; this operation needs a ... journal."; transactions: "Line 1: '...' is not a fixed asset transaction type this operation posts."; "Line 1: post acquisitions with postAcquisition." (or disposals with postDisposal); "Line 1: send either DebitAmount or CreditAmount, as an amount greater than zero."; "Journal name ... posts to the ... posting layer, but book ... posts to the ... posting layer."; an unknown book or reason code; transfer: "Send Dimensions, LocationId or both..."; an unknown location; "Fixed asset ... already has these financial dimensions and this location: there is nothing to transfer."; split: "Send either Percent or Quantity."; a percentage or quantity out of range; the asset itself as receiving asset; reversal: no Voucher; "Voucher ... has transactions of book ... on several dates. Send TransactionDate."; a reversal date before the transaction; an AssetIdExternalKey that does not resolveCorrect the request and resend.
DocumentNotFound (2)Proposal: "Fixed asset book ... was not found."; transfer and split: an unknown asset; reversal: "Book ... of fixed asset ... has no transaction with voucher ..."Send an existing asset, book or voucher.
InvalidStatus (3)"Book ... of fixed asset ... is not acquired yet. Post the acquisition first."; "Book ... of fixed asset ... is Sold and takes no more transactions." (or Scrapped); transfer: a book that is not open or closed; reversal: a transaction already reversed, or itself a reversalPost the acquisition first; nothing more can be posted to a disposed book; a reversed transaction needs nothing more.
DimensionValueNotFound (5)"Offset main account '...' could not be resolved in the chart of accounts."; a financial dimension or value that does not resolveUse an account and dimension values of the legal entity.
ConfigurationMissing (11)"Journal name ... has no voucher number sequence configured."; "Legal entity ... has no ledger with a chart of accounts."; proposal: the reporting currency amounts of the fixed asset parameters are not updated; transactions: the posting profile has no account or no offset account for the transaction type and book (for example bonus depreciation in USMF, whose profile ALL has no bonus depreciation accounts: nothing is posted); transfer: no transfer number sequence; split: "Fixed asset group ... numbers its assets manually, so the split cannot create the new asset."; reversal: no reversal voucher or trace number sequenceFix the setup, then resend. For a split into a manually numbered group, create the receiving asset and send ToAssetId.
BusinessRule (4)D365 refused the post: posting profile accounts, book not acquired, disposal parameters, an unbalanced sale (no offset account), a closed period; "Journal ... was not posted."; transactions: "book ... does not depreciate, so it takes no Depreciation transactions."; transfer: a date outside the fiscal calendar, a book with no transactions to move, a move between balancing dimensions in public sector (transfer it on the Transfer asset page); split: the standard split refused; reversal: "Voucher ... was posted with a vendor transaction. Reverse it in accounts payable." (or customer), a later transaction on the book, a negative net book value, a closed fiscal periodSee below.
PreviewUnsupported (10)PreviewMode true: fixed asset operations have no previewSend without PreviewMode. Nothing was run.
TransientRuntime (6)Infrastructure fault; IsRetryable trueResend with the same RequestId.

A refused post leaves no journal behind. Acquisition, transaction and disposal journals are committed before they are posted. When the post fails, the service deletes the unposted journal again and the failed request releases its RequestId, so fix the cause and resend: the resend creates and posts the journal anew. Only if that cleanup itself fails does the journal stay unposted on Fixed assets journal; delete it, or correct and post it in D365 instead of resending. A transfer, a split and a reversal run in one transaction each: when they fail, nothing is changed (a split that fails creates no receiving asset).

An empty or unexpected proposal. The proposal reports calculation problems as messages rather than failing: when the message says nothing was due but you expected lines, read InformationalMessages.

Replays and stranded requests work as for every posting service: a repeated RequestId returns the first result; see Post a journal exactly-once. A queued operation that fails lands in the dead-letter queue; see Integration operations.

Reference​