Quick Answer
For Dynamics 365 applications that use Microsoft Dataverse, the “Dynamics 365 Web API” is the Dataverse Web API, an OData v4 REST endpoint that lets authenticated applications read and modify business data over HTTPS. Current Microsoft examples use the /api/data/v9.2/ endpoint. You authenticate with Microsoft Entra ID using OAuth, then call table endpoints with standard HTTP methods such as GET, POST, PATCH, and DELETE. For server-to-server integrations, the Microsoft Entra application should also be represented by an application user in the Dataverse environment with an appropriate security role.
Key Takeaways
The Microsoft Dataverse Web API is a RESTful interface for working with Dataverse data and metadata. It implements OData v4, which means developers can use standard HTTP requests and familiar query conventions from virtually any language or platform that can send authenticated HTTPS requests.
For Dynamics 365 products built on Dataverse, including common customer-engagement workloads, developers often refer to this as the D365 Web API or Dynamics CRM API. The distinction is important because Dynamics 365 refers to a family of products. Not every Dynamics 365 ERP application exposes all of its data through this same Dataverse endpoint, so integration teams should confirm the Microsoft Dynamics API surface for the specific Dynamics 365 product they are connecting.
Microsoft’s current Dataverse Web API examples use an organization endpoint in this form:
https://{organization}.api.crm.dynamics.com/api/data/v9.2/{resource}
Version 9.2 is the endpoint version used across current Microsoft Dataverse Web API documentation and samples. If you are maintaining older code that uses an earlier v8.x path, review Microsoft’s current documentation before extending that integration.
The Web API is useful when an external application needs direct, programmatic access to Dataverse records. Common scenarios include:
For lower-code scenarios, Power Automate or a supported connector may be easier to maintain. The Web API becomes especially useful when you need precise request control, custom code, a language-neutral HTTP interface, or integration logic that does not fit an existing connector.
Scheduled jobs and event-driven services can use the Web API to create or update rows, synchronize data between systems, and trigger downstream business logic. For production use, focus not only on making API calls but also on managing authentication, retries, idempotency, concurrency, and service-protection limits over time.
Custom web applications, internal dashboards, mobile tools, and middleware services can use the Web API to surface Dataverse data without reproducing the full Dynamics 365 user interface. Microsoft also provides platform-specific options such as Xrm.WebApi for model-driven app JavaScript and SDK choices for .NET and Python, so the right interface depends on where your code runs.
Dataverse uses OAuth with Microsoft Entra ID. Authentication establishes the identity making the call, while Dataverse security roles and privileges determine which tables, rows, and operations that identity is authorized to use. This distinction is important because receiving an access token does not automatically provide broad access to the environment.
Before sending your first request, confirm the following:
Microsoft’s authentication guidance varies by where the code runs, but external clients generally authenticate through Microsoft Entra ID using OAuth. The steps below focus on an app-only server-to-server pattern because it is common for Microsoft Dynamics integrations and background services.
Create an application registration in Microsoft Entra ID and record the Application (client) ID and Directory (tenant) ID. For a single-tenant internal integration, a single-tenant registration is usually appropriate. The exact registration settings should match your organization’s identity and security requirements.
While a client secret can support server-to-server authentication, it is not the only approach. For production workloads, use the strongest credential model that fits your architecture, such as a certificate or managed identity where supported. If you use a client secret, keep it in a secure secrets store and never commit it to source control or expose it in browser-side code.
For app-only access, create an application user in the target Dataverse environment that corresponds to the Microsoft Entra application, then assign only the security roles and privileges the integration needs. Microsoft specifically recommends using a custom security role for real-world server-to-server applications.
A client-credentials token request uses the Microsoft identity platform token endpoint and the Dataverse organization URL as the resource scope:
POST https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded
client_id={your-client-id}
client_secret={your-client-secret}
scope=https://{your-org}.api.crm.dynamics.com/.default
grant_type=client_credentials
Use the access_token value returned by Microsoft Entra ID as a bearer token. In application code, prefer a supported authentication library such as MSAL when appropriate, and use the token response expiration information or library token cache instead of relying on a fixed lifetime assumption.
Authorization: Bearer {access_token}
Your Dataverse security role still controls what the authenticated application can read or change. A 403 response after successful Dynamics 365 web API authentication often points to an authorization or privilege problem rather than a token problem.
An HTTP client is useful for validating the environment URL, OAuth configuration, headers, table names, and OData query syntax before you move the request into application code. Although Microsoft’s getting-started documentation uses tools like Insomnia and PowerShell, the underlying Microsoft Dynamics API request pattern is the same.
The following request retrieves account names from the first three rows returned by the query:
GET https://{org}.api.crm.dynamics.com/api/data/v9.2/accounts?$select=name&$top=3
Accept: application/json
OData-MaxVersion: 4.0
OData-Version: 4.0
Authorization: Bearer {access_token}
A successful retrieval returns HTTP 200 and a JSON payload. Dataverse responses can include annotations such as @odata.context, record-level @odata.etag values, and @odata.nextLink when more pages of results are available. ETags can be used for conditional operations so an update does not silently overwrite a newer version of a row.
HTTP/1.1 200 OK
Content-Type: application/json
OData-Version: 4.0
{
"@odata.context": "https://{org}.api.crm.dynamics.com/api/data/v9.2/$metadata#accounts(name)",
"value": [
{
"@odata.etag": "W/\"502000\"",
"name": "Contoso Ltd",
"accountid": "89390c24-9c72-e511-80d4-00155d2a68d1"
}
]
}
|
Method |
Purpose |
Common use |
|---|---|---|
|
GET |
Retrieve rows or metadata |
Read accounts, contacts, leads, opportunities, or custom tables |
|
POST |
Create a row or invoke applicable operations |
Create a new account or other table row |
|
PATCH |
Update a row; can also participate in upsert patterns |
Change selected column values without replacing the whole row |
|
DELETE |
Delete a row or clear a supported property |
Remove an existing row |
|
PUT |
Set or replace specific resources in supported scenarios |
Less common for basic table CRUD; follow operation-specific documentation |
For requests that send JSON, include the appropriate Content-Type header. Microsoft samples also commonly send Accept: application/json, OData-MaxVersion: 4.0, and OData-Version: 4.0.
OData query options let you choose columns, filter rows, sort results, limit the returned set, and expand related data. Combine only the options you need, and keep queries as simple and selective as the use case allows.
Use $select to request only the columns your application needs. This reduces payload size and avoids retrieving unnecessary data.
GET /api/data/v9.2/contacts?$select=firstname,lastname,emailaddress1
Use $filter to return only rows that match a condition. Dataverse supports standard OData comparison operators such as eq, ne, gt, ge, lt, and le, along with logical operators and supported query functions.
GET /api/data/v9.2/accounts?$select=name,revenue&$filter=revenue gt 1000000
GET /api/data/v9.2/accounts?$select=name&$filter=contains(name,'Contoso')
Use $orderby to sort results. When paging through a changing data set, deterministic ordering matters. Microsoft recommends including a unique or near-unique value, such as the table primary key, so rows do not unexpectedly overlap between pages.
GET /api/data/v9.2/contacts?$select=lastname,firstname,contactid&$orderby=lastname asc,firstname asc,contactid asc
Use $top when you want only the first N rows from a result set:
GET /api/data/v9.2/accounts?$select=name&$top=10
Do not use $top as a substitute for paging through an entire result set. For OData paging, use the Prefer: odata.maxpagesize request header and follow the @odata.nextLink returned by Dataverse. Dataverse does not support $skip as a paging strategy.
GET /api/data/v9.2/accounts?$select=name,accountid&$orderby=accountid asc
Prefer: odata.maxpagesize=500
Use $expand to retrieve related data through navigation properties defined by the Dataverse data model. Keep expanded projections selective to avoid returning more related data than the application needs.
GET /api/data/v9.2/accounts?$select=name&$expand=primarycontactid($select=fullname,emailaddress1)
Send a POST request to the table’s entity-set endpoint with a JSON body containing the columns you want to populate. If you need the created representation in the response, use Prefer: return=representation.
POST /api/data/v9.2/accounts HTTP/1.1
Content-Type: application/json; charset=utf-8
OData-MaxVersion: 4.0
OData-Version: 4.0
Accept: application/json
{
"name": "Contoso Ltd",
"creditonhold": false,
"revenue": 5000000,
"description": "New account created via Web API"
}
PATCH updates the columns included in the request body. Target the row by its ID, and use conditional headers when you need concurrency protection.
PATCH /api/data/v9.2/accounts(7eb682f1-ca75-e511-80d4-00155d2a68d1) HTTP/1.1
Content-Type: application/json; charset=utf-8
If-Match: W/"502000"
{
"revenue": 7500000,
"description": "Updated via Web API"
}
If the ETag no longer matches because another process changed the row, Dataverse can return HTTP 412 Precondition Failed. Conditional requests are especially useful when multiple systems may update the same business record.
Send DELETE to the row URI when the application is authorized to remove that row:
DELETE /api/data/v9.2/accounts(7eb682f1-ca75-e511-80d4-00155d2a68d1) HTTP/1.1
OData-MaxVersion: 4.0
OData-Version: 4.0
For production integrations, make deletes deliberate and auditable. If the business requirement is to deactivate or close a record rather than physically delete it, use the table’s supported state/status behavior instead.
|
Status |
Likely issue |
Recommended response |
|---|---|---|
|
401 Unauthorized |
Authentication failed or token is invalid/expired |
Acquire a valid token; verify tenant, client, scope/resource, and credential configuration. |
|
403 Forbidden |
Identity is authenticated but not authorized |
Check the Dataverse application user and security-role privileges for the requested table/operation. |
|
404 Not Found |
Wrong environment URL, entity-set name, route, or row ID |
Verify the organization URL, API path, entity-set name, and record identifier. |
|
412 Precondition Failed |
Conditional request failed because the ETag or precondition no longer matches |
Retrieve the current row/ETag and decide whether to retry, merge, or surface a conflict. |
|
429 Too Many Requests |
Dataverse service-protection limit was exceeded |
Honor the Retry-After response header before retrying and reduce sustained or burst load. [5] |
|
5xx Server Error |
Transient service or platform failure may have occurred |
Log the full response and request correlation details; retry only when the operation is safe/idempotent and your retry policy allows it. |
Always capture the response body and relevant request/correlation information when troubleshooting. Avoid logging access tokens, client secrets, or sensitive business data.
Use $select to retrieve only the columns the application actually consumes. This is one of the simplest ways to reduce response size and avoid unnecessary work.
Assume that large result sets will be paged. Use Prefer: odata.maxpagesize, follow @odata.nextLink exactly as returned, and use deterministic ordering when consistency across pages matters. Microsoft documents that a request can return up to 5,000 standard-table rows by default, while other table types and environment behavior can differ, so code should be written to page rather than depend on a single-response assumption.
Never place client secrets in source code, browser JavaScript, or a public repository. Use a managed secret store, rotate credentials according to organizational policy, and assign the Dataverse application user the minimum privileges needed for its integration tasks. If the architecture permits, favor certificate-based or managed identity authentication over long-lived shared secrets.
Dataverse uses service-protection limits to keep the platform responsive. When the Web API returns HTTP 429, Microsoft includes a Retry-After value. Wait for that interval before retrying. Do not use batching or parallelism as a way to bypass limits because Dataverse also evaluates execution time and concurrent requests.
Retries can create duplicate work if an operation is not idempotent. For integration jobs, decide how you will recognize already-processed messages, use alternate keys or upsert patterns where appropriate, and use ETags or conditional headers when concurrent updates are possible.
Track request latency, error rates, 429 frequency, Dynamics 365 API authentication failures, retries, and business-level reconciliation failures in your application telemetry. The goal is to detect a data-sync problem before it becomes a user-visible Dynamics 365 issue.
In the context of Dynamics 365 applications that store their business data in Microsoft Dataverse, “Dynamics 365 Web API” and “Dataverse Web API” generally refer to the same Dataverse OData endpoint. Microsoft’s current documentation uses the Dataverse name.
However, it is too broad to say that every Dynamics 365 product uses one identical API. Dynamics 365 includes multiple applications and workloads. If you are integrating with Finance, Supply Chain Management, Business Central, or another product-specific service, verify that product’s current MS Dynamics API documentation before assuming the Dataverse endpoint is the right integration surface.
The Microsoft Dataverse Web API gives development and Dynamics 365 API integration teams a standards-based way to connect Dataverse-backed Dynamics 365 applications with the rest of the technology stack. The basic mechanics of a successful proof of concept are simple: authenticate, access the correct entity set, and handle JSON data. Production quality depends on the details around identity, authorization, query design, paging, retries, concurrency, observability, and data governance.
IES helps organizations plan, implement, and support Microsoft Dynamics 365 integrations. If you are deciding between the Dataverse Web API, Power Platform connectors, Azure integration services, or a product-specific integration approach, contact IES to discuss the architecture that best fits your environment.