AB-400 · CHEAT SHEET
Microsoft Certified: Power Platform Developer Associate
Key concepts grouped by official exam weight.
Download as PDF (free, no sign-up)1. Build Microsoft Power Platform solutions
15–20%Design the technical architecture
- Before writing any code, a PL-400 developer needs to translate business requirements into concrete technical building blocks: is this a plug-in, a Power Automate flow, a PCF component, or an external integration? The technical architecture documents each piece, its dependencies, and the reasoning behind the choice, steering clear of over-engineering or fragile solutions.
- Every component (plug-in, custom connector, Azure Function, app) needs an identity strategy: interactive users authenticate via OAuth/Microsoft Entra ID, while unattended processes rely on service principals or managed identities. Authorization then layers on top through Dataverse security roles that constrain what each component can read or write.
- The PL-400 'low-code first' principle: before writing custom code, check whether business rules, Power Automate flows, views, or calculated columns already solve the requirement without it. Building a plug-in or a custom component is only justified when the platform has no native way to deliver that capability.
- The same business logic can live in different layers: business rules (declarative, lightweight), client-side scripting (UI validation), server-side plug-ins (synchronous, transactional), or Power Automate (asynchronous orchestration). Picking the right layer affects performance, maintainability, and whether the logic also applies outside the UI.
- Standard tables store data inside Dataverse; virtual tables surface external data as if it were native without duplicating it; elastic tables are built for high-volume, semi-structured data such as telemetry or logs; connectors reach external data on demand without modeling it as a table at all. The right choice depends on volume, latency, and whether you need relationships.
Design solution components
- Canvas components (reusable building blocks inside the low-code editor) and PCF code components (written in TypeScript) solve different problems: the former for UI/logic shared across canvas apps, the latter when you need full control of the DOM, better performance, or integration with external JS libraries — even inside model-driven apps.
- A custom connector wraps a REST API — your own or a third party's — in an OpenAPI definition so Power Apps and Power Automate can consume it like any built-in connector. Designing one means deciding on authentication, which operations to expose, and how to group them so they don't collide with DLP policies.
- Power Fx functions in Dataverse extend calculated columns with reusable logic; plug-ins run synchronous C# code in response to platform events; custom APIs define bespoke operations invocable as Web API messages, each with its own input/output contract.
- Designing a flow instead of writing code makes sense when the logic is mostly cross-system orchestration — waiting, approving, notifying — rather than heavy computation. The design should account for error handling and concurrency, and decide which parts are better delegated to a plug-in or Azure Function instead of living inside the flow itself.
- Outbound integrations typically use Service Endpoints/Webhooks or Azure Service Bus to notify external systems when a record changes; inbound integrations use the Web API, custom APIs, or connectors to let external systems write into Dataverse. The choice comes down to whether you need a synchronous response or looser decoupling.
Implement application lifecycle management (ALM)
- Dataverse solutions automatically track dependencies between components — for example, a plug-in that references a specific column. These dependencies prevent deleting or changing a component that something else relies on, and determine what must be included when exporting a solution so it works correctly in another environment.
- Environment variables externalize values that change between environments — API URLs, keys, connection IDs — so the same component works in dev, test, and production without touching code. They're defined once in the solution and given a different value per environment, avoiding hardcoded configuration.
- When multiple solutions — unmanaged and managed, from different publishers — modify the same component, Dataverse stacks them in layers, and only the active top layer determines the visible behavior. Understanding layering is essential for figuring out why a change 'isn't showing up' or conflicts with another solution.
- Power Platform Pipelines automate solution deployment across environments (dev to test to prod) directly from the Power Platform interface, without manually wiring up Azure DevOps. They can be extended with custom stages or checks when the standard deployment flow doesn't cover a project's specific needs.
- Power Platform Build Tools are Azure DevOps tasks (with GitHub Actions equivalents) that export, package, version, and import solutions automatically as part of a CI/CD pipeline, letting you enforce quality gates — solution checker, automated tests — before anything reaches production.
2. Extend the user experience
25–30%Apply business logic in model-driven apps by using client scripting
- The Client API exposes objects like formContext and Xrm to read and write attributes, control field visibility, show notifications, or navigate within model-driven forms. Coding against this object model — rather than manipulating the DOM directly — is the supported, stable way to write client scripts.
- Event handlers (OnLoad, OnChange, OnSave) can be registered statically in the form designer or dynamically at runtime with addOnChange/addOnSave. The choice affects whether the handler survives the form being reopened and how easy it is to debug or remove.
- Client-side JavaScript can make asynchronous calls to the Web API (Xrm.WebApi) to read or update related records without reloading the form — for example, validating a value against another table before saving. That's a different capability from just manipulating the fields already on the current form.
- The ribbon/command bar of a model-driven app is customized with enable rules and command actions — configurable declaratively with Power Fx today, or with JavaScript for more complex logic — controlling when a button shows up and what it does when clicked.
- Custom pages are canvas surfaces embedded inside a model-driven app. You navigate to them programmatically with Xrm.Navigation.navigateTo, passing input parameters — useful for guided workflows or bespoke interfaces the standard form simply can't provide.
Create PCF code components
- A PCF component goes through well-defined lifecycle events: init (once, on load), updateView (whenever the data changes), getOutputs (to return values to the framework), and destroy (cleanup). Implementing these correctly avoids memory leaks and inconsistent behavior.
- The ControlManifest.Input.xml file declares a PCF component's properties (bound/unbound), resources (scripts, CSS, images), and platform features (Device, Utility, WebAPI) it needs. It's the first thing Power Apps reads to know how to render the component and what data to feed it.
- A PCF component implements the ComponentFramework.StandardControl (or ReactControl) interface, with required methods like init and updateView, and correctly typed input/output parameters defined in the manifest so the framework can talk to the component at runtime.
- A PCF component is packaged as a solution (via pac pcf push or bundled into a Dataverse solution), deployed to the environment, and then 'consumed' by adding it to a specific field, form, or canvas app from the relevant designer.
- A PCF component's context object exposes extra capabilities when declared in the manifest: context.device (camera, geolocation, microphone), context.utils (formatting, dialogs), and context.webAPI (reading/writing Dataverse) — extending what a component can do beyond just rendering data.
Build Power Apps code apps
- To connect a code app to a connector, use the CLI: `pa connector list`, `pa connection create`, and `pa app add data-source` (with `--table`/`--dataset` when tabular, like SQL or SharePoint), which generates a TypeScript model and service. For portability across environments use a connection reference (`--connection-ref`/`--solution-id`); not all connectors are supported, such as Excel Online.
- To use Dataverse as a data source, run `pa app add data-source --connector dataverse --table <logical-name>` in a Dataverse-enabled environment, generating a TypeScript model and service. The service supports create, read, update, and delete, with delegation for filter, sort, and top, and paging. Not supported: polymorphic lookups, entity metadata CRUD, FetchXML, and alternate keys.
- The table service exposes `create`, `get`, `getAll`, `update`, and `delete`; `getAll` accepts `IGetAllOptions` (select, filter, orderBy, top, skipToken), and columns should be limited with `select`. Updates should include only the changed properties. `getMetadata` retrieves entity, column, and relationship metadata, but not derived-type properties (choice-column options); lookups are associated using `@odata.bind`.
- To call a Dataverse action or function, search with `pa app find-dataverse-api --search <name>` (a substring match on the name), then add it with `pa app add dataverse-api --api-name <name>`, which generates a TypeScript model and service. For a bound action (e.g. `AddToQueue`), the service call's first argument is the ID of the record it operates on; unbound functions such as `WhoAmI` don't require one.
- Code apps can only invoke solution-aware instant cloud flows that use the Power Apps trigger; scheduled flows, automated flows, and other triggers are not supported. Flows are added with `pa app add flow --flow-id <id>`, which downloads the OpenAPI definition and generates a TypeScript service with a static `Run` method. The maker needs access to the flow and its connections, and end users need Dataverse permissions, such as the App Opener role, to invoke it.
Deploy and manage Power Apps code apps
- A code app's Content Security Policy (CSP) is configured at the environment level in the Power Platform admin center (Settings > Product > Privacy + Security > Content security policy > App), or via the Power Platform API. By default connect-src is 'none', blocking unallowed outbound calls. Turn on Enable reporting and test first before switching on Enforce content security policy.
- To monitor a code app with Azure Application Insights, install `@microsoft/applicationinsights-web` and register a logger with `setConfig` from `@microsoft/power-apps/app`, which receives metrics like sessionLoadSummary and networkRequest. If CSP is enforced, add the endpoint to connect-src. Application Insights only captures telemetry after a successful load; startup failures only show in Monitor.
- A code app is compiled with `npm run build` and published with `pa app push` (Power Apps CLI). An admin must first enable the feature on the environment (Settings > Product > Features > Enable code apps), and end users need a Power Apps Premium license. `pa app push` adds the app to a Dataverse solution for cross-environment ALM, and `pa app share` grants play or edit access.
- To debug a code app, use browser dev tools (F12), filtering the Network tab by apihub.net (connectors) or dynamics.com (Dataverse). The admin center's Monitor area provides metrics like Time to interactive and Data request success rate/latency. Application Insights only logs telemetry after a successful load; startup failures only show in Monitor.
- A code app's performance is tracked in Monitor through the Data request latency and Data request success rate metrics; many 429 errors call for reducing data calls. Calls to the Dataverse Web API are subject to the same service protection limits as any client (requests, execution time, and concurrent requests within five minutes), and very large batches raise the risk of hitting the execution-time limit.
3. Extend Microsoft Power Platform
35–40%Create a Dataverse plug-in
- The Dataverse event pipeline has 4 stages: PreValidation (10, before the transaction starts, even before the security check), PreOperation (20, inside the transaction, ideal for modifying data before it's saved), MainOperation (30, reserved for the platform), and PostOperation (40, after saving, for side effects). Registering a plug-in at the wrong stage is a common source of bugs.
- IPluginExecutionContext gives access to the target entity, the message (Create, Update...), the user executing the action, the execution depth (to prevent infinite loops), and the collection of input/output parameters — the starting point for practically any plug-in.
- A typical plug-in validates data, calculates derived values, or applies rules spanning multiple tables before or after a Dataverse operation — all within the same transaction that triggered the event, guaranteeing consistency if something fails and gets rolled back.
- Pre-images capture a record's state before the operation (useful on Update/Delete to compare previous values), while Post-images capture the state after. Both are configured when registering the plug-in step, saving you an extra round trip to Dataverse to fetch that data.
- Inside a plug-in, IOrganizationService (obtained via IOrganizationServiceFactory) lets you Create, Update, Delete, or Retrieve against Dataverse, automatically honoring the security context of the user who triggered the event — or an impersonated user's context when needed.
Perform operations by using platform APIs
- The Web API is a RESTful/OData interface for operating on Dataverse from outside the platform (or from client-side JavaScript): GET to query with $select/$filter/$expand, POST to create, PATCH to update, and DELETE to remove — always using the plural entity set name.
- The Organization service is the .NET SDK (SOAP under the hood) for talking to Dataverse from server-side code: plug-ins, console apps, or Azure Functions. It offers the same messages as the Web API but with strong C# typing through IOrganizationService.
- Dataverse enforces request limits per user/application within a time window; exceeding them returns a 429 error with a Retry-After header. A robust client should catch that status code, wait the indicated time, and retry with exponential backoff instead of failing outright.
- For large volumes, prefer ExecuteMultipleRequest or $batch (Web API) over individual calls, group related operations into a single transaction when they must succeed or fail together, and use optimistic concurrency with ETags to avoid accidental overwrites.
- Programmatic access to Dataverse (Web API or Organization service) requires an OAuth 2.0 token issued by Microsoft Entra ID, obtained through the client credentials flow (unattended processes) or an interactive flow (end user), sent as an Authorization: Bearer header on every request.
Process workloads by using Microsoft Azure Functions
- When an operation exceeds the time limits of a synchronous plug-in (2 minutes) or a flow, it gets delegated to an Azure Function, which can run longer processes asynchronously (or with the durable pattern) and report the result back to Power Platform when it's done.
- Besides being invoked over HTTP from a flow or plug-in, an Azure Function can be triggered by a timer (for scheduled tasks like nightly cleanups) or by events from other Azure services (Service Bus, Event Grid), integrating with Power Platform in a decoupled way.
- A managed identity lets an Azure Function authenticate against Dataverse without storing secrets or keys in code: Azure handles the credentials automatically, and you only need to grant that identity the necessary permissions as an application user in Power Platform.
Configure Power Automate cloud flows and Copilot Studio workflows
- Power Automate's expression language (functions like if(), coalesce(), formatDateTime(), references to triggerBody() or previous steps' outputs) allows conditional logic and data transformation inside a single step without an extra action — though overusing it makes the flow harder to maintain.
- Scopes combined with 'run after' settings (has failed, has timed out, is skipped) let you build try/catch-style blocks: if one step fails, a parallel scope catches the error, logs it, or sends a notification — instead of letting the whole flow simply fail with no handling.
- The trigger condition (OData triggerCondition) prevents the flow from running when a change doesn't meet a specific condition, saving unnecessary executions; each action's retry policy defines how many times, and at what interval, a step that fails due to a transient error gets retried.
- A child flow, invoked via the 'Power Apps' trigger or 'when a flow is called from another flow,' encapsulates shared logic — like sending a standard notification — so multiple parent flows can reuse it instead of duplicating the same steps in each one.
- For a flow to authenticate against an API or Azure service without using a specific user's identity, you register a service principal in Microsoft Entra ID with specific permissions, and the flow uses its credentials (client ID/secret or certificate) for HTTP calls.
Build Microsoft Foundry agents by using code that integrates with the Microsoft Power Platform
- Dataverse can act as a remote MCP server at https://{org}.crm.dynamics.com/api/mcp, exposing tools such as read_query, search_data, describe, create_record, and upsert_skill. Copilot Studio is enabled by default; other clients must be enabled in the Power Platform admin center, and the direct remote endpoint needs a custom Entra app with the mcp.tools permission. The server enforces Dataverse's existing security roles and row-level security.
- A Copilot Studio agent can connect to another Copilot Studio agent in the same environment, or to external agents such as Microsoft Foundry, Microsoft 365 Agents SDK, or A2A agents. Connecting a Foundry agent requires the Activity protocol endpoint to be enabled; connecting an Agents SDK agent requires its messaging endpoint URL. A main agent with its own connected agents can't also be used as a connected agent under a different main agent.
- Work IQ is the intelligence layer that gives Microsoft 365 Copilot and agents shared context drawn from files, meetings, messages, and business systems. Dataverse intelligence builds on that foundation so agents can understand and act on Dataverse data through reusable business context. The Work IQ MCP catalog includes a Dataverse and Dynamics 365 server with CRUD operations, governed from the Microsoft 365 admin center.
- The Copilot Studio client in the Microsoft 365 Agents SDK lets code in .NET, JavaScript, or Python invoke an agent that still runs remotely. The connection is configured with a connection string from the Channels page, or with the Environment ID, Tenant ID, and Schema name, plus an Entra app holding the Copilot Studio.Copilots.Invoke permission. If the calling app uses a service principal token, Direct Line must be used instead.
4. Develop integrations
10–15%Publish and consume Dataverse events
- From a plug-in registered on a service endpoint, IServiceEndpointNotificationService lets you explicitly forward the current event's message — with its execution context — to Azure Service Bus or a webhook in code, rather than relying solely on the step's declarative configuration.
- The most common way to publish events is registering a 'Service Endpoint' in the Plug-in Registration Tool (pointing to a webhook, Service Bus, or Event Hub), then a step that ties it to a specific message/entity — no need to hand-write publishing code.
- Each endpoint type fits a different use case: webhooks for notifying a single HTTP receiver directly, Service Bus for reliable point-to-point or queued messaging, and Event Hub when you need large-scale event ingestion — telemetry, streaming.
- Reacting to Dataverse changes from outside the platform has several options depending on the scenario: service endpoints/webhooks for real-time push notifications, Power Automate as a low-code orchestration layer, or polling with change tracking when an immediate reaction isn't necessary.
Implement synchronization for Dataverse data
- Change tracking lets an external system request only the records that changed since the last sync (using a continuation token) instead of downloading the whole table every time — the foundation for efficient incremental sync scenarios with Dataverse.
- Alternate keys let you identify and reference a Dataverse record using a business identifier — a product code, say — instead of the internal GUID, which is especially useful in integrations where the external system has no knowledge of that GUID.
- UpsertRequest creates the record if it doesn't exist or updates it if it does — typically identifying it by an alternate key — sparing you from doing a Retrieve first just to decide manually between Create and Update in sync scenarios with external systems.
Create custom connectors
- A custom connector supports several authentication schemes: API Key, Basic, OAuth 2.0 (the most common for enterprise APIs), or Azure AD/Entra ID. Setting it up correctly means registering the client app with the identity provider and mapping the token parameters in the connector definition.
- Policy templates are runtime transformations applied without touching the backend: adding headers, rewriting the URL, setting default values, or converting date/time formats — handy for adapting an existing API to what Power Platform expects.
- Instead of writing the definition from scratch, you can import it directly from an OpenAPI file, from an Azure resource (like a Function App with Swagger enabled), or from a repository of certified connectors on GitHub, speeding up connector creation.
- Azure services like Functions, Logic Apps, or API Management can be exposed directly as a custom connector straight from the Azure portal, or by importing their OpenAPI definition — keeping managed authentication (managed identity or Azure keys) integrated with Power Platform.
- An Azure Function can act as a custom connector's backend: it receives the connector's call, runs logic (transformation, aggregation, calling another system), and returns a JSON response. It needs to expose its own OpenAPI definition for the connector creation wizard to recognize it.