
Key Takeaways
- The Microsoft Dynamics 365 Web API is a RESTful service built on OData v4, enabling developers to interact with Dynamics 365 CRM and ERP data using standard HTTP methods.
- All modern implementations should use API version v9.2 (e.g., /api/data/v9.2/).
- Authentication requires registering an application in Microsoft Entra ID (formerly Azure Active Directory) and obtaining an OAuth 2.0 access token before making any API calls.
- The API supports full CRUD operations (Create, Read, Update, and Delete) via POST, GET, PATCH, and DELETE HTTP methods.
- OData query options like $select, $filter, $orderby, $top, and $expand give developers precise control over the data returned by each request.
- Best practices include paginating large result sets, limiting returned fields with $select, securing client secrets, and implementing retry logic for 429 rate-limit errors.
What Is the Microsoft Dynamics 365 Web API?
The Microsoft Dynamics 365 Web API is a RESTful web service that gives developers programmatic access to Dynamics 365 data and functionality over HTTPS. It is the standard integration layer for both CRM (Customer Relationship Management) and ERP (Enterprise Resource Planning) workloads inside the Dynamics 365 platform.
The Web API is built on OData v4, an OASIS standard for building and consuming RESTful APIs. Because it follows open standards, the API is compatible with virtually any programming language or platform, including C#, JavaScript, Python, and Java. Developers use standard HTTP verbs – GET, POST, PATCH, and DELETE – to retrieve, create, update, and remove records.
Unlike the older Organization Service (SOAP-based), the Web API is the recommended approach for all new integrations. It runs on the same underlying Dataverse platform that powers Microsoft Power Apps and Power Automate, so capabilities added to Dataverse are immediately accessible through the Web API.
As of time of writing, all modern implementations use API version v9.2. The path follows this pattern:
https://{organization}.api.crm.dynamics.com/api/data/v9.2/{resource}
Version 8.2, which appeared in documentation published in 2016 and 2017, is outdated. Microsoft replaced it with the v9.x series, which introduced significant improvements to batch processing, metadata handling, and OData compliance. Use v9.2 for all new work.
Why Use the Dynamics 365 Web API?
The Dynamics 365 Web API gives developers and IT teams a single, standards-based interface for everything they need to do with Dynamics 365 data. Below are the four primary use cases.
Integrate Dynamics 365 With Other Applications
The Web API makes it straightforward to connect Dynamics 365 with external systems, e.g., marketing platforms, ERP systems, ecommerce solutions, or proprietary line-of-business applications. Because it follows REST and OData standards, any platform that can make an HTTPS request can integrate with Dynamics 365 without a custom connector.
Common integrations include:
- Syncing customer records between Dynamics 365 and Power BI dashboards
- Pushing lead data from web forms directly into Dynamics CRM
- Connecting Dynamics 365 with Azure Logic Apps or Power Automate to trigger automated workflows across systems
Automate Business Processes
Manual data entry and repetitive administrative tasks are prime candidates for automation through the Dynamics 365 API. Teams commonly use it to do things like auto-create records when events occur in connected systems, run scheduled data synchronization jobs between Dynamics 365 and external databases, and trigger follow-up tasks in Dynamics CRM based on actions taken in other applications.
Power Automate integration makes this accessible to non-developers: flows can call the Dynamics 365 REST API endpoints without writing code, while developers can build more complex automation logic in C# or Python.
Build Custom Applications
Many organizations need functionality that goes beyond the standard Dynamics 365 interface. The Web API is the foundation for custom portals, mobile apps, and internal tools that surface Dynamics 365 data in tailored experiences. Developers can build customer-facing portals that read and write CRM records in real time, internal dashboards that pull Dynamics 365 data into custom reporting views, and mobile applications that give field teams access to account and contact records without opening the full Dynamics interface.
Access Data Securely Through OAuth
The Web API enforces OAuth 2.0 authentication for every request. This means applications never handle user passwords directly. Instead, they exchange client credentials for a short-lived access token issued by Microsoft Entra ID, which is included as a bearer token in each API call. Dynamics 365 security roles control what each authenticated identity can read or modify, so the API respects your existing role-based access control configuration automatically.
Microsoft Dynamics 365 API Prerequisites
Before making your first API call, four things need to be in place.
Microsoft Entra ID (aka Azure Active Directory)
Microsoft Entra ID is the identity platform that issues OAuth access tokens for Dynamics 365 API requests. Your organization needs an active Microsoft Entra ID tenant, which is included with any Microsoft 365 or Dynamics 365 subscription. You will use the Entra ID portal to register your application and manage its permissions. Your organization may still refer to this as Azure Active Directory (Azure AD), so you should know that both terms refer to the same service; Microsoft rebranded it to Microsoft Entra ID in 2023.
Dynamics 365 Environment
You need an active Dynamics 365 environment (also called an instance or organization). This can be a production environment, a sandbox, or a developer environment. Free developer environments are available through the Microsoft Power Apps Developer Plan, which is a practical option for testing and learning. Note your environment’s URL, which will be the base of all your API requests. It follows this format:
https://{your-org-name}.api.crm.dynamics.com
Application Registration
API calls made from code (server-to-server integrations, scripts, background services) require a registered application in Microsoft Entra ID. The registration process assigns your application a client ID and lets you configure a client secret or certificate for authentication. Delegated permissions work differently, since they allow an application to make API calls on behalf of a signed-in user, but application permissions are more common for integrations and automation.
Required Permissions
The registered application needs the Dynamics CRM permission user_impersonation (for delegated access) or appropriate application permissions granted in Entra ID. In addition, the Dynamics 365 user account associated with your integration needs the appropriate security roles assigned inside Dynamics 365 itself. API authentication succeeding does not automatically grant access to all data, since Dynamics 365 role-based access control applies to every record the API returns or modifies.
How to Authenticate to the Dynamics 365 Web API
Authentication to the Dynamics 365 Web API uses the OAuth 2.0 client credentials flow (for server-to-server integrations) or the authorization code flow (for user-delegated access). The steps below cover the client credentials approach, which is the most common for integrations.
Register an App in Microsoft Entra ID
Navigate to the Microsoft Entra admin center (https://entra.microsoft.com) and select App registrations. Click New registration, give your application a name, and choose the appropriate supported account type (typically “Single tenant” for internal integrations). You do not need a redirect URI for the client credentials flow.
Generate Client ID and Secret
After registration, the Overview page shows your Application (client) ID and Directory (tenant) ID – copy both. Then navigate to Certificates & secrets, click New client secret, set an expiration period, and copy the value immediately. You cannot retrieve the secret value after you leave the page. Store it securely in Azure Key Vault or an equivalent secrets manager, never in source code.
Configure API Permissions
In your app registration, go to API permissions and click Add a permission. Select Dynamics CRM, choose user_impersonation (delegated) or the appropriate application permission, and click Add permissions. For application-level access, click Grant admin consent for your tenant. You also need to add your application as a user inside Dynamics 365 under Settings > Users.
Obtain an OAuth Access Token
Exchange your client credentials for an access token by sending a POST request to the Microsoft identity platform token endpoint:
POST https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token
Include the following form-encoded body parameters:
client_id={your-client-id}
client_secret={your-client-secret}
scope=https://{your-org}.api.crm.dynamics.com/.default
grant_type=client_credentials
The response returns a JSON object containing an access_token value. Include this token as a Bearer token in the Authorization header of every subsequent API request:
Authorization: Bearer {access_token}
Access tokens expire after approximately one hour. Your application should handle token refresh automatically by re-requesting a token when a 401 response is received.
Making Your First Dynamics 365 Web API Request
Test the API Using Postman
Postman is the fastest way to test the Dynamics 365 Web API without writing code. To get started, create a new request collection, set up an OAuth 2.0 authorization configuration with your tenant ID, client ID, and client secret, and point it at the token URL above. Once authenticated, you can send GET requests directly to your Dynamics 365 environment URL and inspect the responses.
In Postman, set the Authorization type to OAuth 2.0 and configure a new token using the client credentials grant type. Postman should handle the token exchange automatically and attach the bearer token to each request. This lets you iterate on query parameters and inspect raw JSON responses before implementing the same logic in code.
Example GET Request
The following request retrieves the name field from the first three account records in Dynamics 365:
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}
Understanding the Response
A successful response returns HTTP 200 with a JSON body. The value array contains the matching records:
HTTP/1.1 200 OK
Content-Type: application/json; odata.metadata=minimal
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"
},
{
"@odata.etag": "W/\"502001\"",
"name": "Fabrikam Inc",
"accountid": "8b390c24-9c72-e511-80d4-00155d2a68d1"
}
]
}
The @odata.context value confirms the endpoint and selected fields. The @odata.etag on each record is used for concurrency control when updating records with PATCH. If the result set is paginated, an @odata.nextLink property appears at the root level with the URL for the next page.
HTTP Methods Used in the Dynamics 365 API
The Dynamics 365 Web API uses five standard HTTP methods to perform all data operations:
|
Method |
Purpose |
Common Use |
|
GET |
Retrieve records |
Query accounts, contacts, leads, custom entities |
|
POST |
Create records |
Create new accounts, cases, opportunities |
|
PATCH |
Update records |
Update fields on existing records; also used for upsert |
|
DELETE |
Delete records |
Remove a record or clear a single property |
|
PUT |
Replace single property |
Update a single entity attribute directly |
All requests must include the Accept: application/json and OData-MaxVersion: 4.0 headers. Requests that include a body (POST, PATCH) also require Content-Type: application/json.
Querying Data with OData
OData query options are the primary mechanism for filtering, shaping, and sorting the data the Web API returns. They are appended to the entity set URL as query string parameters. It is possible to combine multiple options in a single request.
Using $select
$select limits the response to specific columns, reducing payload size and improving performance. Without it, the API returns all fields on every record, which can be slow and bandwidth-intensive.
GET /api/data/v9.2/contacts?$select=firstname,lastname,emailaddress1
This returns only the first name, last name, and email address for each contact record instead of all 80+ contact fields.
Using $filter
$filter applies conditions to limit which records are returned. It supports standard OData comparison operators (i.e., eq, ne, gt, lt, ge, le) and logical operators (i.e., and, or, not).
GET /api/data/v9.2/accounts?$select=name,revenue&$filter=revenue gt 1000000
This retrieves accounts with annual revenue over $1,000,000. You can combine conditions:
GET /api/data/v9.2/leads?$select=fullname,statuscode&$filter=statuscode eq 1 and createdon gt 2024-01-01
String functions are also available: contains(name,'Contoso'), startswith(name,'A'), endswith(emailaddress1,'microsoft.com').
Using $orderby
$orderby sorts the result set by one or more fields. Append asc or desc to specify direction. The default is ascending.
GET /api/data/v9.2/opportunities?$select=name,estimatedvalue&$orderby=estimatedvalue desc
Sort by multiple fields by separating them with commas:
GET /api/data/v9.2/contacts?$select=lastname,firstname&$orderby=lastname asc,firstname asc
Using $top
$top limits the number of records returned. The Dynamics 365 Web API returns a maximum of 5,000 records per page by default. Use $top to retrieve a smaller set.
GET /api/data/v9.2/accounts?$select=name&$top=10
For larger data sets, use the Prefer: odata.maxpagesize={n} header to set your preferred page size, then follow the @odata.nextLink URL in each response to retrieve subsequent pages:
GET /api/data/v9.2/accounts?$select=name
Prefer: odata.maxpagesize=50
If the result set has more records than the page size, the response includes an @odata.nextLink property with the URL for the next page. Issue a new GET request to that URL to continue paginating.
Using $expand
$expand retrieves related records in a single request, similar to a JOIN in SQL. It follows navigation properties defined in the Dynamics 365 metadata.
GET /api/data/v9.2/accounts?$select=name&$expand=primarycontactid($select=fullname,emailaddress1)
This returns each account’s name along with the full name and email of its primary contact, all in one request. You can combine $expand with $filter and $select on the expanded entity:
GET /api/data/v9.2/opportunities?$select=name,estimatedvalue
&$expand=customerid_account($select=name,revenue;$filter=revenue gt 500000)
Create, Update, and Delete Records
Create Records with POST
Send a POST request to the entity set endpoint with a JSON body containing the fields to populate. The response is HTTP 204 with no body by default, but you can request the full created record by including the Prefer: return=representation header.
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"
}
A successful create returns HTTP 204 No Content. The OData-EntityId response header contains the URI of the newly created record, including its GUID. To receive the full record in the response body with a 201 Created status code, add the Prefer: return=representation header.
Update Records with PATCH
PATCH updates only the fields included in the request body, leaving all other fields unchanged. Target the specific record by appending its GUID to the entity set URL.
PATCH /api/data/v9.2/accounts(7eb682f1-ca75-e511-80d4-00155d2a68d1) HTTP/1.1
Content-Type: application/json; charset=utf-8
OData-MaxVersion: 4.0
OData-Version: 4.0
{
"revenue": 7500000,
"description": "Updated via Web API"
}
A successful PATCH returns HTTP 204 No Content. To prevent overwriting concurrent changes, include an If-Match header with the record’s current ETag value. If the record has been modified since you last retrieved it, the API returns 412 Precondition Failed.
PATCH can also perform an upsert: if the specified GUID does not exist, the API creates the record. Include If-Match: * to update only (fail if not found), or If-None-Match: * to create only (fail if already exists).
Delete Records with DELETE
Send a DELETE request targeting the record URI. A successful delete returns HTTP 204 No Content.
DELETE /api/data/v9.2/accounts(7eb682f1-ca75-e511-80d4-00155d2a68d1) HTTP/1.1
OData-MaxVersion: 4.0
OData-Version: 4.0
To delete a single property value rather than the entire record, append the property name to the URI:
DELETE /api/data/v9.2/accounts(7eb682f1-ca75-e511-80d4-00155d2a68d1)/description
Common Dynamics 365 Web API Errors and Solutions
|
Error Code |
Meaning |
Common Cause |
Solution |
|
401 Unauthorized |
Authentication failed |
Expired or invalid access token |
Re-authenticate to obtain a fresh token; verify client ID and secret are correct |
|
403 Forbidden |
Access denied |
Missing Dynamics 365 security role |
Check the user or app’s security role assignment inside Dynamics 365 |
|
404 Not Found |
Resource not found |
Wrong URL, entity name, or record GUID |
Verify the entity name (plural), environment URL, and API version (v9.2) |
|
412 Precondition |
Concurrency conflict |
ETag mismatch on PATCH or DELETE |
Re-retrieve the record to get the current ETag and retry |
|
429 Too Many Req. |
Rate limit exceeded |
Too many API calls in a short window |
Implement exponential backoff and retry; check API call limits for your license |
|
500 Server Error |
Internal server error |
Issue on the Dynamics 365 platform side |
Check the error details in the response body; review the Dynamics 365 service health page |
The response body for all errors follows a consistent structure including an error code and message property. Always log the full response body, not just the status code, to diagnose issues efficiently.
Best Practices for Using the Dynamics 365 Web API
Limit Returned Fields
Always include $select in your requests to return only the fields your application needs. Dynamics 365 entities can have hundreds of fields, and retrieving all of them unnecessarily increases response payload size, slows down queries, and consumes more API call capacity. For large-volume integrations, the difference between selecting 5 fields and returning all fields can be a 10x difference in response time.
Use Pagination
Never assume all results fit in a single response. Use the Prefer: odata.maxpagesize header to set an explicit page size and always check for @odata.nextLink in the response. Process each page sequentially rather than attempting to retrieve all results at once. For very large data sets, consider using Dataverse batch requests or FetchXML-based paging cookies for more efficient pagination.
Secure Client Secrets
Client secrets must never be embedded in source code, stored in version control, or exposed in client-side JavaScript. Use Azure Key Vault to store secrets and retrieve them at runtime via managed identity. Rotate secrets before they expire using the expiration date set during creation. If a secret is compromised, revoke it immediately in the Microsoft Entra ID portal and issue a new one.
Implement Retry Logic
Transient failures and rate limit responses (429) are normal in production environments. Implement exponential backoff: on a 429 response, wait for the duration specified in the Retry-After response header before retrying.
For 500 errors, use an exponential backoff starting at 1 second, doubling up to a maximum of 60 seconds, with a maximum of three to five retry attempts. Log all retries for observability.
Monitor API Usage
Dynamics 365 enforces service protection API limits based on the number of requests, execution time, and concurrent requests per user or application over a five-minute sliding window. Monitor your application’s API consumption through the Dynamics 365 admin center and Azure Monitor. Set up alerts if call volume approaches limit thresholds. Applications that regularly hit rate limits should be redesigned to batch operations, cache frequently read data, or distribute load across multiple service accounts.
Harness the Full Power of Dynamics 365
The Microsoft Dynamics 365 Web API gives your team a standards-based, secure, and flexible interface for connecting Dynamics 365 to the rest of your technology ecosystem. Whether you’re building your first integration, automating a manual workflow, or architecting a full custom application on Dataverse, the Web API is the right foundation.
IES brings years of expertise in Microsoft Dynamics 365 solutions to help businesses unlock the full potential of their CRM and ERP environments. Contact us to learn how IES can help you integrate, extend, and get more from your Dynamics 365 investment.
Dynamics 365 Web API: FAQs
Connecting to the Dynamics 365 API requires four steps
- Register an application in Microsoft Entra ID
- Generate a client ID and client secret
- Grant the application the Dynamics CRM user_impersonation permission (and admin consent)
- Use those credentials to request an OAuth 2.0 access token from the Microsoft identity platform.
Include the token as a Bearer token in the Authorization header of all API requests. Server-to-server integrations use the client credentials flow; user-facing applications use the authorization code flow.
Two OAuth flows are commonly used: the client credentials flow for server-to-server integrations where no user is interactively present, and the authorization code flow for applications that act on behalf of a signed-in user. Legacy Windows-integrated authentication (i.e., Active Directory) is still supported for on-premises Dynamics 365 deployments.
There is no difference; they are the same API. Microsoft Dataverse is the underlying data platform that powers Dynamics 365 CRM and ERP applications, Power Apps, and Power Automate. The Dynamics 365 Web API and the Dataverse Web API are both accessed at the same endpoint (/api/data/v9.2/) on the same environment URL.
The distinction is mainly in terminology. When working with Dynamics 365 applications most people call it the Dynamics 365 Web API; when working with custom Power Apps tables or platform features they call it the Dataverse API. On a functional level (e.g., authentication and query syntax) they are identical.
In Postman, create a new collection and set the Authorization type to OAuth 2.0. Configure a new token with the grant type set to Client Credentials, the access token URL set to https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token, and your client ID and client secret from the Entra ID app registration.
Set the scope to https://{your-org}.api.crm.dynamics.com/.default. Click Get New Access Token, then Use Token. You can now send requests to your Dynamics 365 environment URL — for example, a GET to /api/data/v9.2/accounts?$select=name&$top=5 to retrieve your first five account names.
Dynamics 365 enforces service protection limits per user or application identity over a five-minute sliding window. The three limits are:
- Number of requests (varies by license, typically 6,000 per five minutes)
- Combined execution time (20 minutes per five minutes)
- Concurrent requests (52 at any one time).
Exceeding any of these returns a 429 Too Many Requests response with a Retry-After header indicating how many seconds to wait. Organizations with high-volume integration needs can purchase additional API call capacity or optimize their integrations to batch requests using the $batch endpoint.


