D365 F&O: Structuring Dataverse Payloads with Power Fx UDTs

Power Automate and Power Apps with D365 F&O · 10 min read
TL;DR: Power Fx User Defined Types (UDTs) are now Generally Available as of Studio v3.26044. Discover how to build compile-time type-safe payloads for D365 Finance & Operations integrations.
D365 F&OPower AppsDataverseIntegrationArchitecture

When designing front-end Canvas Apps that stage multi-line sales orders, batch inventory movements, or procurement requests into Dynamics 365 Finance & Operations via Dataverse, architects have long wrestled with weakly typed records and brittle JSON parsing. Passing dynamic objects between nested canvas components, custom APIs, and backend entities frequently created silent conversion errors and unexpected schema drift. With Power Fx User Defined Types (UDTs) reaching General Availability, you can now enforce compile-time schemas directly inside your Power Apps formulas to guarantee rock-solid integration contracts with D365 F&O.

At a glance

  • 🔹 Applies to: Microsoft Dynamics 365 Supply Chain Management, Dynamics 365 Finance, Power Apps Studio (v3.26044 or later), Dataverse Custom APIs, Virtual Entities, and Dual-Write.
  • 🔹 Prerequisites: Power Apps Studio version 3.26044+, Environment Maker permissions, Dataverse security role with read/write access to ERP virtual tables or custom staging tables.
  • 🔹 Effort level: Low to medium (formula refactoring and schema definition in App.Formulas).
  • 🔹 Outcome: Deterministic, strongly typed contract and parse-time payload validation between Canvas Apps and D365 F&O data entities, preventing runtime schema rejections and malformed OData requests.

How it works

Historically, Power Fx handled complex objects either through implicit inference from connectors or untyped dynamic structures generated by ParseJSON. When a field sales rep created an order containing lines, discounts, serial allocations, and date boundaries, canvas apps had to rely on cumbersome manual transformations like Value(Text(ThisItem.Price)) or DateValue(...). Any missing property or localized date format (such as MM/DD/YYYY instead of RFC 3339 YYYY-MM-DD) yielded runtime execution faults or corrupt records inside Dataverse staging tables and D365 F&O OData endpoints.

Power Fx User Defined Types solve this by introducing formal schema definitions using the Type function within the App.Formulas declaration. By establishing explicit type signatures for headers and lines, makers define immutable contracts for app-level operations. When paired with User Defined Functions (UDFs), ParseJSON validates inbound payloads against the declared UDT at instantiation. If a property violates the schema, Power Fx halts processing immediately with diagnostic errors or allows graceful type checks through IsType and AsType before sending payloads to Dataverse custom tables or D365 F&O virtual entities.

📝 NoteKey Architectural Rule: Power Fx UDT definitions must be declared inside the App.Formulas property using the definition operator (:=). Declaring them inside App.OnStart is unsupported and will fail validation.
Payload Lifecycle with Power Fx UDTs
Figure 1: Figure 1: Architectural flow from Canvas App UI entry to strongly typed Dataverse and D365 F&O dispatch.

The following architectural comparison illustrates how traditional untyped payload handling contrasts with modern Power Fx User Defined Types when integrating with D365 Finance & Operations:

Integration Dimension Untyped Dynamic Records (Legacy) Power Fx User Defined Types (Current GA)
Schema Enforcement Runtime evaluation; silent failures when attributes are missing. Design-time and parse-time type checking with explicit errors.
Date & Time Handling Manual string slicing or error-prone DateValue() calls. Strict RFC 3339/ISO 8601 parsing directly into native Date objects.
Component Contracts Complex untyped record properties; easily broken by updates. Strongly typed parameters on Enhanced Component Properties.
D365 Entity Alignment OData payloads fail on mismatched types during dual-write/virtual table write. Direct alignment with D365 F&O data entity schemas before network dispatch.
Developer Experience No IntelliSense autocomplete on parsed JSON structures. Full property autocompletion, type hinting, and compile-time validation.

Step-by-step solution

  1. 1. Enable User Defined Types in App Settings

    Navigate to your Canvas App in Power Apps Studio. Open Settings > Updates > New and toggle User-Defined types to On. In apps created in Studio version 3.26044 or higher, this feature is enabled by default. Save and reopen your app to ensure the updated settings take effect.
  2. 2. Model ERP Entities into Power Fx Types

    Select the App object in the tree view and switch to the Formulas property in the formula bar. Define separate record contracts for your sales order lines and sales order headers to mirror D365 F&O data entities like SalesOrderHeaderV2Entity and SalesOrderLineV2Entity.
    // App.Formulas declaration
    SalesLineRecordType := Type( {
        ItemNumber: Text,
        OrderedSalesQuantity: Number,
        SalesPrice: Number,
        SalesUnitSymbol: Text,
        RequestedReceiptDate: Date,
        ShippingSiteId: Text,
        ShippingWarehouseId: Text
    } );
    
    SalesHeaderRecordType := Type( {
        SalesOrderNumber: Text,
        InvoiceCustomerAccountNumber: Text,
        OrderingCustomerAccountNumber: Text,
        CurrencyCode: Text,
        DataAreaId: Text,
        Lines: [ SalesLineRecordType ]
    } );
  3. 3. Derive Sub-Schemas using RecordOf

    When managing gallery controls or single-record parameter passing, use the RecordOf function to generate an explicit single-row type from your defined table contracts without duplicate definitions. This ensures child components accept only valid line item structures.
    // Derive singular item contract from table type
    SalesLineTableType := Type( [ SalesLineRecordType ] );
    SingleLineContract := Type( RecordOf( SalesLineTableType ) );
  4. 4. Validate Incoming JSON Payloads

    When consuming order responses or external JSON structures, execute ParseJSON referencing your declared UDT. Power Fx automatically verifies type conformity and parses standard ISO dates without manual string conversions.
    Set(
        StronglyTypedOrder,
        ParseJSON(
            RawPayloadString,
            SalesHeaderRecordType
        )
    );
  5. 5. Implement Safe Dynamic Checking with IsType and AsType

    To avoid runtime execution interruptions when parsing untrusted external inputs from barcode scanners or webhook events, implement defensive checks using IsType before casting with AsType.
    If(
        IsType( DynamicPayload, SalesHeaderRecordType ),
        Set( StronglyTypedOrder, AsType( DynamicPayload, SalesHeaderRecordType ) ),
        Notify("Invalid schema: Missing required D365 ERP fields.", NotificationType.Error)
    );
  6. 6. Dispatch Typed Payloads to Dataverse Virtual Entities

    Create a User Defined Function (UDF) in App.Formulas that accepts the strongly typed record and persists it to Dataverse staging tables or directly to D365 F&O Virtual Entities (such as mserp_salesorderheaderv2entity).
    StageOrderToDataverse( order: SalesHeaderRecordType ) : Void = {
        Patch(
            'Sales order headers V2 (mserp)',
            Defaults( 'Sales order headers V2 (mserp)' ),
            {
                mserp_salesordernumber: order.SalesOrderNumber,
                mserp_invoicecustomeraccountnumber: order.InvoiceCustomerAccountNumber,
                mserp_orderingcustomeraccountnumber: order.OrderingCustomerAccountNumber,
                mserp_currencycode: order.CurrencyCode,
                mserp_dataareaid: order.DataAreaId
            }
        )
    };
💡 Pro tipPro Tip: When working with D365 F&O Virtual Entities, Dataverse automatically exposes the underlying entity columns with the prefix mserp_. Map these exact names inside your UDF parameter consumer to streamline patching.

Worked example

At Contoso Industrial Supplies, field sales technicians use a rugged tablet Canvas App to record site orders for heavy equipment spare parts. The app operates in company USMF. Previously, field technicians submitted orders containing multiple line items. The app staged untyped records in Dataverse, which were then synchronized to D365 F&O SalesOrderHeaderV2Entity and SalesOrderLineV2Entity.

Contoso frequently suffered failed transactions because date formats differed across tablet locales (causing D365 OData 400 Bad Request exceptions: "The requested date cannot be converted to UTC date"), and technicians occasionally omitted mandatory site identifiers. Implementing Power Fx UDTs completely stabilized this interface.

⚠️ Watch outWatch Out for Strict Date Validation: ParseJSON using a UDT strictly requires RFC 3339 formatted dates (e.g., "2026-05-15"). Supplying non-compliant strings like "05/15/2026" immediately throws an error: "Expected value to be a valid RFC 3339 'full-date' or 'date-time' format".

The solution team defined strict contracts in App.Formulas:

// Contoso USMF Sales Architecture Schema
ContosoSalesLine := Type( {
    LineNum: Number,
    ItemId: Text,
    Qty: Number,
    Price: Number,
    Site: Text,
    Warehouse: Text,
    ReceiptDate: Date
} );

ContosoOrderPayload := Type( {
    OrderNumber: Text,
    CustomerAccount: Text,
    Company: Text,
    Lines: [ ContosoSalesLine ]
} );

// Strongly typed order dispatcher
PostContosoOrder( payload: ContosoOrderPayload ) : Void = {
    Patch(
        'Contoso Order Staging Headers',
        Defaults( 'Contoso Order Staging Headers' ),
        {
            cr123_ordernumber: payload.OrderNumber,
            cr123_customeraccount: payload.CustomerAccount,
            cr123_dataareaid: payload.Company,
            cr123_status: "Validated"
        }
    );
    ForAll(
        payload.Lines,
        Patch(
            'Contoso Order Staging Lines',
            Defaults( 'Contoso Order Staging Lines' ),
            {
                cr123_ordernumber: payload.OrderNumber,
                cr123_itemid: ItemId,
                cr123_quantity: Qty,
                cr123_salesprice: Price,
                cr123_site: Site,
                cr123_warehouse: Warehouse,
                cr123_receiptdate: ReceiptDate
            }
        )
    )
};

By enforcing this schema at the UI boundary, invalid date formats and missing warehouse entries are trapped directly in the tablet client before network dispatch. Following deployment, Contoso eliminated client-side date-parsing exceptions and prevented malformed records from reaching Dataverse and D365 F&O.

0%
Date Parsing Errors
-91%
Validation Latency
100%
OData Sync Stability
Sales Order Staging Integration Metrics (Before vs After UDTs)
Figure 3: Comparison of field sales staging integration metrics at Contoso Industrial Supplies.

Automation and AI opportunities

Integrating Power Fx UDTs unlocks key capabilities when orchestrating workflows with Microsoft Copilot Studio and Power Automate. When generative AI agents extract sales lines from unstructured customer PDF invoices or email RFQs, the output can be funneled through ParseJSON(aiRawResponse, SalesHeaderRecordType). If the agent hallucinated a field name or outputted a currency string instead of a decimal, the UDT immediately flags the violation without polluting D365 F&O data tables.

Furthermore, D365 F&O Business Events (such as SalesOrderConfirmedBusinessEvent) firing into Dataverse Custom Actions can be bound to canvas notification components that use UDT-typed properties. This ensures event payloads containing warehouse reservation statuses are consumed seamlessly across low-code UI controls with zero data conversion ambiguity.

Common pitfalls and troubleshooting

  • Symptom: ParseJSON throws an unhandled error: "Expected value to be a valid RFC 3339 'full-date' or 'date-time' format".
    Cause: The input JSON contains a localized date string (such as "12/31/2026") rather than standard ISO 8601/RFC 3339 ("2026-12-31").
    Fix: Ensure upstream systems or Power Automate flows format dates using formatDateTime(utcNow(), 'yyyy-MM-dd'), or use IsType to detect non-conforming records and sanitize them prior to parsing.
  • Symptom: Compiler flags unknown identifier or syntax errors on the Type() statement in the formula bar.
    Cause: The formula was written inside App.OnStart, or the feature flag was turned off.
    Fix: Ensure the app is updated to Studio v3.26044+, navigate to Settings > Updates > New, enable User-Defined types, and move all type declarations strictly into App.Formulas.
  • Symptom: Dataverse virtual entity updates succeed but mandatory D365 F&O fields arrive as blank or default values.
    Cause: Property names in the UDT do not match the exact naming contract consumed in the Patch statement for mserp_* fields.
    Fix: Review the entity metadata in Dataverse. Ensure your UDF explicitly maps each UDT property directly to its target field (for example, mapping payload.Warehouse to mserp_inventlocationid).
  • Symptom: App authoring performance degrades when opening complex canvases with extensive nested UDT hierarchies.
    Cause: Defining recursive or excessively circular record structures in App.Formulas.
    Fix: Decouple hierarchical models. Define line item record types independently, and use RecordOf or flat sub-tables rather than deeply nested structures exceeding 3 levels of depth.
  • Symptom: IsType returns false despite the payload appearing visually identical to the schema.
    Cause: Power Fx enforces strict scalar type checks; passing a numeric value as a string (such as "150.00" instead of 150.00) causes validation to fail.
    Fix: Verify upstream JSON serialization headers. Ensure numbers and booleans are not quoted as string literals in upstream API outputs.

Best-practice checklist

  • ✅ Declare all User Defined Types centrally in App.Formulas using PascalCase naming conventions (e.g., SalesOrderLineType).
  • ✅ Leverage RecordOf to maintain DRY (Don't Repeat Yourself) principles between table schemas and singular record parameter contracts.
  • ✅ Always sanitize external JSON timestamps to RFC 3339 format before applying ParseJSON against a UDT.
  • ✅ Combine UDTs with Enhanced Component Properties to create robust, reusable UI libraries across your Power Platform environment.
  • ✅ Pair UDT validation with D365 F&O Virtual Entities to trap data corruption before sending web requests across the Dataverse OData gateway.
  • ✅ Use IsType and AsType to implement defensive fallbacks for optional or variable payload elements.
  • ✅ Document your UDT models in Git repository ALM solutions alongside canvas app unpack pipelines (PAC CLI).

FAQ

Can I define User Defined Types dynamically inside screen-level formulas?

No. Power Fx User Defined Types are design-time schema declarations. They must reside in the App.Formulas property of the App object so that the compiler can evaluate types globally across screens, components, and user-defined functions.

Do Power Fx UDTs require a Power Apps Premium license?

The UDT feature itself is an engine capability available in standard and premium apps alike. However, using them to read or write to Dataverse, D365 F&O Virtual Entities, or custom staging tables requires appropriate Power Apps Premium licensing or qualifying Dynamics 365 enterprise user rights.

Can UDTs enforce regex patterns or numeric boundary constraints?

UDTs currently enforce primitive structural types (Text, Number, Date, Boolean, Record, Table). Value-level constraints (such as checking if a quantity is greater than zero or validating a 10-digit customer code) must still be evaluated using business logic in your User Defined Functions or UI validators.

Key takeaways

Power Fx User Defined Types Architecture
Figure 2: Figure 2: Component architecture and integration capabilities provided by Power Fx UDTs.
  • User Defined Types eliminate runtime type guessing, providing compile-time contracts between Canvas Apps and D365 F&O.
  • Pairing UDTs with ParseJSON automatically resolves ISO date strings and validates record completeness before touching Dataverse.
  • Using typed schemas across UDFs and Canvas Components dramatically reduces dual-write and OData payload rejections in production ERP environments.

Further reading

Note: written with AI assistance and reviewed by Gaurav Jadaun. Always validate in a sandbox environment before applying to production.

Comments

Popular posts from this blog

Monthly Inventory Close in Microsoft Dynamics AX 2012

Product Configuration Technology Ax2012R3

How to configure Fixed Assets Module in Ax2012