Tools

Mastering Dynamics 365 Web API with Postman

March 31, 2025
Sabhat Qureshi
10 min read

What is Postman?

Postman is one of the most widely used API development and testing platforms. For Dynamics 365 consultants and developers, Postman serves as an indispensable tool for exploring the Web API, testing queries, debugging integration issues, and prototyping API calls before implementing them in code. Postman.

The Dynamics 365 Web API is a RESTful OData v4.0 endpoint that provides programmatic access to your organization's data and metadata. Using Postman to interact with this API allows you to quickly test queries, validate authentication flows, inspect response structures, and troubleshoot issues without writing a single line of code.

Why use Postman with Dynamics 365?

  • Rapid prototyping: Test API queries and operations before implementing them in plugins or external applications
  • Authentication testing: Validate OAuth flows and troubleshoot token-related issues in a controlled environment
  • API discovery: Explore available entities, actions, and functions using the $metadata endpoint
  • Integration debugging: Reproduce and diagnose API errors reported by external systems
  • Performance analysis: Measure API response times and identify performance bottlenecks
  • Documentation: Create and share collections as living API documentation for your team

Getting started: Installation and setup

Installing Postman

Postman is available as a desktop application for Windows, macOS, and Linux. While a web version exists, the desktop app offers better performance and offline capabilities.

Installation steps:

  1. Download Postman from postman.com/downloads
  2. Install the application following the installer prompts
  3. Create a free Postman account or sign in with Google/GitHub
  4. Create a workspace for your Dynamics 365 projects
  5. Familiarize yourself with the interface: Collections, requests, environments

đź’ˇ Pro tip:

Create separate workspaces for different clients or projects. This keeps your collections organized and makes it easy to share specific API collections with team members without exposing unrelated work.

Authentication setup with OAuth 2.0

Dynamics 365 Web API requires OAuth 2.0 authentication using Microsoft Entra ID (formerly Azure Active Directory). Setting up authentication correctly is crucial—without it, all your API requests will fail with 401 Unauthorized errors. OAuth authentication guide.

Microsoft Entra ID app registration

Before you can authenticate from Postman, you need to register an application in Microsoft Entra ID. This creates the client credentials needed for OAuth authentication.

App registration steps:

  1. Navigate to the Azure portal (or the Microsoft Entra admin center) and select "Microsoft Entra ID"
  2. Click "App registrations" → "New registration"
  3. Name: "Postman Dynamics 365 Web API" (or similar)
  4. Supported account types: "Accounts in this organizational directory only"
  5. Redirect URI: Select "Web" and enter https://oauth.pstmn.io/v1/callback
  6. Click "Register" and note the Application (client) ID
  7. Navigate to "Certificates & secrets" → "New client secret"
  8. Add description (e.g., "Postman Access") and set expiration
  9. Copy the secret value immediately (it won't be shown again)
  10. Navigate to "API permissions" → "Add a permission"
  11. Select "Dynamics CRM" → "Delegated permissions"
  12. Check "user_impersonation" → "Add permissions"
  13. Click "Grant admin consent" if you have admin privileges

⚠️ Security warning:

Client secrets are sensitive credentials. Store them securely in password managers, never commit them to source control, and rotate them regularly (every 90 days recommended). Consider using certificate-based authentication for production scenarios.

Configuring OAuth 2.0 in Postman

Once your Microsoft Entra ID app is registered, configure Postman to use these credentials for authentication. Postman's OAuth 2.0 implementation handles the token acquisition and renewal automatically.

Configuration steps:

  1. In Postman, create a new request or collection
  2. Open the "Authorization" tab
  3. Select "OAuth 2.0" in the Type dropdown
  4. Click "Get New Access Token" to configure the OAuth settings
  5. Fill in the following fields:
    • Token Name: "D365 Access Token"
    • Grant Type: "Authorization Code"
    • Callback URL: https://oauth.pstmn.io/v1/callback
    • Auth URL: https://login.microsoftonline.com/YOUR_TENANT_ID/oauth2/v2.0/authorize
    • Access Token URL: https://login.microsoftonline.com/YOUR_TENANT_ID/oauth2/v2.0/token
    • Client ID: the Application (client) ID of your app registration in Microsoft Entra ID
    • Client Secret: the secret value you copied earlier
    • Scope: https://YOUR_ORG.crm.dynamics.com/.default
  6. Click "Request Token": a browser window opens so you can sign in
  7. Sign in with your Dynamics 365 account
  8. Once you are signed in, click "Use Token"

đź’ˇ Environment variables:

Instead of hardcoding values, create Postman environment variables for tenant_id, client_id, client_secret, and org_url. This makes it easy to switch between DEV, TEST, and PROD environments without reconfiguring authentication.

CRUD operations with the Web API

The Dynamics 365 Web API supports standard RESTful CRUD operations using HTTP methods: GET (retrieve), POST (create), PATCH (update), and DELETE. Understanding these operations is fundamental to working with the API. Web API operations documentation.

1. Create (POST)

Creating records requires a POST request with a JSON body containing the entity data. The response includes the URI of the newly created record in the OData-EntityId header.

Example: create an account

Request:

POST https://YOUR_ORG.crm.dynamics.com/api/data/v9.2/accounts

Headers:

Content-Type: application/json
Accept: application/json
OData-MaxVersion: 4.0
OData-Version: 4.0

Body (JSON):

{
  "name": "Contoso Corporation",
  "telephone1": "+1-555-0123",
  "emailaddress1": "info@contoso.com",
  "address1_city": "Seattle",
  "address1_stateorprovince": "WA",
  "industrycode": 1,
  "revenue": 5000000
}

2. Retrieve (GET)

GET requests retrieve data from Dynamics 365. You can retrieve single records, collections, or use query options to filter, sort, and shape the response.

Example: retrieve an account with $select and $expand

Request:

GET https://YOUR_ORG.crm.dynamics.com/api/data/v9.2/accounts(GUID)?$select=name,revenue,telephone1&$expand=primarycontactid($select=fullname,emailaddress1)

Common query options:

  • $select: Choose specific columns to return (improves performance)
  • $filter: Apply filter conditions (e.g., revenue gt 1000000)
  • $orderby: Sort results (e.g., createdon desc)
  • $top: Limit number of results (e.g., $top=10)
  • $expand: Include related records in the response
  • $count: Include total count of matching records

3. Update (PATCH)

PATCH requests update existing records. Only include the fields you want to update—unchanged fields should be omitted. Use PATCH instead of PUT for partial updates.

Example: update an account's revenue

Request:

PATCH https://YOUR_ORG.crm.dynamics.com/api/data/v9.2/accounts(GUID)

Body (JSON):

{
  "revenue": 7500000,
  "description": "Updated after Q1 review"
}

4. Delete (DELETE)

DELETE requests permanently remove records from Dynamics 365. Use with caution, especially in production environments. Consider deactivation (status update) instead of deletion for audit trail preservation.

Example: delete an account

Request:

DELETE https://YOUR_ORG.crm.dynamics.com/api/data/v9.2/accounts(GUID)

Advanced operations

Batch requests

Batch requests allow you to bundle multiple operations into a single HTTP request, significantly reducing network overhead and improving performance. batch operations.

Batch request structure:

Request:

POST https://YOUR_ORG.crm.dynamics.com/api/data/v9.2/$batch

Headers:

Content-Type: multipart/mixed;boundary=batch_AAA123
Accept: application/json

Body:

--batch_AAA123
Content-Type: application/http
Content-Transfer-Encoding: binary

POST /api/data/v9.2/accounts HTTP/1.1
Content-Type: application/json

{
  "name": "Account 1",
  "revenue": 100000
}

--batch_AAA123
Content-Type: application/http
Content-Transfer-Encoding: binary

POST /api/data/v9.2/accounts HTTP/1.1
Content-Type: application/json

{
  "name": "Account 2",
  "revenue": 200000
}

--batch_AAA123--

Batch request best practices:

  • Limit batch size to 100 operations for optimal performance
  • Use change sets for transactional operations (all-or-nothing)
  • Mix read and write operations in the same batch
  • Handle partial failures gracefully—batch responses include individual operation results
  • Monitor API service protection limits when using batch operations

FetchXML queries

FetchXML is a proprietary query language for Dynamics 365 that supports complex queries including aggregates, grouping, and outer joins. FetchXML reference.

Example: run a FetchXML query

Request:

GET https://YOUR_ORG.crm.dynamics.com/api/data/v9.2/accounts?fetchXml=<fetch><entity name='account'><attribute name='name'/><attribute name='revenue'/><filter><condition attribute='revenue' operator='gt' value='1000000'/></filter><order attribute='revenue' descending='true'/></entity></fetch>

FetchXML tips:

  • URL-encode FetchXML queries when passing as query parameters
  • Use FetchXML Builder in XrmToolBox to visually design complex queries
  • Leverage aggregate functions (sum, avg, count, min, max) for reporting
  • Use link-entity for joins across related tables
  • Add paging to large result sets using page and count attributes

Actions and functions

Dynamics 365 exposes business logic through Actions (POST operations with side effects) and Functions (GET operations without side effects). These include both system actions (like WinOpportunity, QualifyLead) and custom actions you create.

Example: call the WinOpportunity action

Request:

POST https://YOUR_ORG.crm.dynamics.com/api/data/v9.2/WinOpportunity

Body (JSON):

{
  "OpportunityClose": {
    "subject": "Won the deal!",
    "opportunityid@odata.bind": "/opportunities(GUID)"
  },
  "Status": 3
}

Error handling and troubleshooting

Understanding error responses is crucial for debugging API issues. Dynamics 365 Web API returns detailed error messages in JSON format following OData error conventions.

Common HTTP status codes

  • 200 OK: Successful GET or PATCH operation
  • 201 Created: Successful POST operation (new record created)
  • 204 No Content: Successful DELETE or PATCH operation with no return value
  • 400 Bad Request: Invalid request syntax or validation errors
  • 401 Unauthorized: Authentication failure or expired token
  • 403 Forbidden: Insufficient privileges for the operation
  • 404 Not Found: Entity or record doesn't exist
  • 412 Precondition Failed: Concurrency check failed (record was modified)
  • 429 Too Many Requests: API service protection limits exceeded

Error response structure

When an error occurs, the response body tells you exactly what went wrong:

{
  "error": {
    "code": "0x80040217",
    "message": "You do not have permission to access these records.",
    "innererror": {
      "message": "Principal user (Id=...) is missing prvReadAccount privilege",
      "type": "System.ServiceModel.FaultException",
      "stacktrace": "..."
    }
  }
}

Debugging checklist

  • Verify OAuth token is valid and not expired (check token expiration time)
  • Ensure proper headers are included (Content-Type, OData-MaxVersion, Prefer)
  • Validate JSON syntax in request body using a JSON validator
  • Check entity and attribute logical names match exactly (case-sensitive)
  • Confirm user has sufficient privileges for the operation
  • Review service protection limit headers (x-ms-ratelimit-*) in responses
  • Use Postman Console (View → Show Postman Console) to inspect raw requests/responses

⚠️ Service protection limits:

Dynamics 365 implements service protection API limits to ensure fair resource usage. Monitor these headers in responses: x-ms-ratelimit-burst-remaining-xrm-requests (requests per minute) and x-ms-ratelimit-time-remaining-xrm-requests (execution time). Implement exponential backoff retry logic when you receive 429 responses.

Best practices for production use

Performance optimization

  • Use $select: Always specify only the columns you need—reduces payload size and improves performance
  • Implement paging: Use $top and $skiptoken for large result sets instead of retrieving all records
  • Leverage batch requests: Bundle multiple operations to reduce HTTP request overhead
  • Cache metadata: Entity definitions, option sets, and other metadata rarely change—cache them client-side
  • Use conditional requests: Implement If-Match headers for optimistic concurrency control
  • Minimize $expand depth: Nested expands impact performance—retrieve related data separately if needed

Security considerations

  • Principle of least privilege: Use service accounts with minimal required permissions
  • Secure credential storage: Never hardcode credentials—use Azure Key Vault or secure environment variables
  • Token management: Implement proper token refresh logic before expiration (typically 1 hour lifetime)
  • Input validation: Sanitize all user inputs to prevent injection attacks
  • HTTPS only: Always use HTTPS for API communications (enforced by Dynamics 365)
  • Audit logging: Enable audit logging in Dynamics 365 to track API-based data changes

Testing and documentation

  • Create collections: Organize related requests into Postman collections for reusability
  • Use environments: Create environment variables for DEV, TEST, PROD to switch contexts easily
  • Write tests: Add Postman test scripts to validate responses automatically
  • Generate documentation: Use Postman's documentation feature to share API examples with team
  • Export collections: Version control your Postman collections as JSON files in Git
  • Monitor APIs: Use Postman monitors to run scheduled health checks on critical endpoints

Postman collection templates

Creating a well-organized Postman collection saves time and standardizes API interactions across your team.

Collection organization

  • Authentication: Folder with token acquisition examples and refresh flows
  • Metadata: Requests to explore entities, attributes, and relationships using $metadata
  • CRUD operations: Subfolders per entity (accounts, contacts, opportunities) with create/read/update/delete examples
  • Queries: Advanced filtering, sorting, and FetchXML examples
  • Actions & functions: System actions (WinOpportunity, QualifyLead) and custom actions
  • Batch operations: Batch request templates for bulk operations
  • Testing & diagnostics: Health check endpoints and troubleshooting queries

đź’ˇ Collection variables:

Use collection-level variables for values that don't change between environments (like API version "v9.2") and environment-level variables for values that differ per environment (like org_url, tenant_id). This creates a clean separation of concerns.

Advanced Postman features

Pre-request scripts

Pre-request scripts execute before sending a request, enabling dynamic behavior like generating timestamps, computing signatures, or checking token expiration.

Example: refresh the OAuth token automatically

// Check if token exists and is not expired
const tokenExpiry = pm.environment.get("token_expiry");
const now = Date.now();

if (!tokenExpiry || now >= tokenExpiry) {
    // Token expired - get new token
    console.log("Token expired, requesting new token...");
    // Trigger OAuth flow or refresh token logic
}

Test scripts

Test scripts run after receiving a response, allowing you to validate status codes, response structure, and data values automatically.

Example: validate the account creation

pm.test("Status code is 201 Created", function () {
    pm.response.to.have.status(201);
});

pm.test("Response has OData-EntityId header", function () {
    pm.response.to.have.header("OData-EntityId");
});

// Extract account ID from response
const entityId = pm.response.headers.get("OData-EntityId");
const accountId = entityId.match(/\(([^)]+)\)/)[1];
pm.environment.set("new_account_id", accountId);
console.log("Created account ID: " + accountId);

Collection runner

Collection Runner executes all requests in a collection sequentially or with custom iteration logic. Perfect for integration testing, data seeding, or performance testing.

  • Run entire collections to validate end-to-end workflows
  • Use data files (CSV, JSON) to parameterize requests for bulk testing
  • Generate test reports to share results with stakeholders
  • Schedule runs using Newman (Postman's CLI) in CI/CD pipelines

Integrating Postman with development workflow

From Postman to code

One of Postman's most valuable features is code generation. After perfecting an API request in Postman, generate equivalent code in C#, JavaScript, Python, or other languages.

Code generation steps:

  1. Create and test your request in Postman until it works correctly
  2. Click the code icon (</>) in the request panel
  3. Select your target language/framework (C#, JavaScript, Python, etc.)
  4. Copy the generated code into your application
  5. Refactor as needed for your architecture (error handling, retry logic, etc.)

Version control and team collaboration

Treat your Postman collections as code artifacts. Export collections and environments as JSON files and commit them to your repository for version control and team sharing.

  • Export collections regularly and commit to Git repository
  • Use Postman workspaces for team collaboration and sharing
  • Document breaking changes in collection descriptions
  • Create separate branches for experimental API changes
  • Review collection changes in pull requests like application code

Conclusion

Mastering Postman for Dynamics 365 Web API development dramatically accelerates your productivity as a consultant or developer. From rapid prototyping of API calls to comprehensive integration testing, Postman provides the tooling necessary to work efficiently with the Web API.

Start by setting up authentication correctly, organize your work into well-structured collections, leverage environment variables for flexibility, and gradually incorporate advanced features like batch requests and test scripts.

Remember to always test in development environments first, implement proper error handling, respect service protection limits, and document your API patterns for team knowledge sharing. The investment in building comprehensive Postman collections pays dividends throughout the project lifecycle.

Need help with your Dynamics 365 project?

I can help you apply these practices in your own Dynamics 365 environment.