Dataverse Web API 101

Tim Hanewich
8 min readSep 7, 2022

Dataverse is low-code/no-code friendly data service for storing both structured and unstructured data behind a role-based security model. Dataverse is a pillar of Microsoft’s Power Platform and the backbone of Microsoft’s Dynamics 365 first party applications. Dataverse is designed to be as easy-to-use and robust for small workloads while also being scalable and performant enough to handle enterprise workloads on a massive scale.

In addition to being used with it’s numerous integrations with other Microsoft and 3rd party products, Dataverse also supports direct interfacing via the Dataverse Web API, a RESTful API. This article is intended to get you started with using the Dataverse Web API. By the end of the article, you will be prepared to start querying the Dataverse API!

Medium

Since the Dataverse API is web-based, all requests must go through the Hypertext Transfer Protocol (HTTP). This is just a fancy way of saying each request to the API will look similar to a URL, like what you’d see in your browser.

We have to be able to customize components of each HTTP request: URL, request headers, body, etc. Because of this, we will be using Postman, a free application for customizing these components of an HTTP request, sending to the API, and receiving the response.

You can download Postman here: Postman Download

Authentication

Authentication will likely be the most challenging aspect of this article. There are two ways that I will document how you can authenticate; the first is the “correct” way of doing things, and the second is a faster, easier to understand way.

When calling the Dataverse API, you don’t directly provide your credentials (username/password) each time you make a single request. Instead, you authenticate with the API once, an Access Token is provided to you, and you then provide this Access Token to the API each time you make a request. Keep in mind that this token does expire however (usually in 60 minutes from the time it was received), so after the expiration time, you’ll have to do it again to get a new token!

Authenticating via an Access Token Request

One can make an HTTP POST request with the following characteristics to receive an access token:

  • HTTP Method: POST
  • URL: https://login.windows.net/common/oauth2/token
  • Body: x-www-form-urlencoded format with the following values:
  • grant_type: password
  • client_id: 51f81489-12ee-4a9e-aaae-a2591f45987d
  • resource: (the URL of your Dataverse environment)
  • username: (your username)
  • password: (your password)

After constructing the request as specified above, hit send! If all goes well, you’ll receive a response like the following:

{
"token_type": "Bearer",
"scope": "user_impersonation",
"expires_in": "4817",
"ext_expires_in": "4817",
"expires_on": "1655742922",
"not_before": "1655737804",
"resource": "https://org9422ae7b.crm.dynamics.com/",
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImpTMVhvMU9XRGpfNTJ2YndHTmd2UU8yVnpNYyIsImtpZCI6ImpTMVhvMU9XRGpfNTJ2YndHTmd2UU8yVnpNYyJ9.eyJhdWQiOiJodHRwczovL29yZzk0NDJhZTdiLmNybS5keW5hbWljcy5jb20vIiwiaXNzIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvMWU4NWYyM2YtYzBhZi00YmNlLWJiOTYtOTIwMTRkM2MxMzU5LyIsImlhdCI6MTY1NTczNzgwNCwibmJmIjoxNjU1NzM3ODA0LCJleHAiOjE2NTU3NDI5MjIsImFjciI6IjEiLCJhaW8iOiJFMlpnWUFqOCtZZWhjTVZoNXI0NHVZYWNpeFVHRTFOZDJJUnlXUXNxR2RiNVBabmI5Z3NBIiwiYW1yIjpbInB3ZCJdLCJhcHBpZCI6IjUxZjgxNDg5LTEyZWUtNGE5ZS1hYWFlLWEyNTkxZjQ1OTg3ZCIsImFwcGlkYWNyIjoiMCIsImZhbWlseV9uYW1lIjoiQWRtaW5pc3RyYXRvciIsImdpdmVuX25hbWUiOiJTeXN0ZW0iLCJpcGFkZHIiOiI0Ny4yMDIuMTIuMjgiLCJuYW1lIjoiU3lzdGVtIEFkbWluaXN0cmF0b3IiLCJvaWQiOiIzNTAzYzUzMy1kZmI5LTRlNDktYmNhZC00N2VkYzgzYzA2NTUiLCJwdWlkIjoiMTAwMzIwMDEzQzIxQTM5MyIsInJoIjoiMC5BWHdBUF9LRkhxX0F6a3U3bHBJQlRUd1RXUWNBQUFBQUFBQUF3QUFBQUFBQUFBQjhBQUUuIiwic2NwIjoidXNlcl9pbXBlcnNvbmF0aW9uIiwic3ViIjoiQkpPeTdRcFJRYk1TTTVjLS1zZlh5aVEyU2t3ZThqdkdzWHNiR0ZuWXlsWSIsInRpZCI6fjFlODVmMjNmLWMwYWYtNGJjZS1iYjk2LTkyMDE0ZDNjMTM1OSIsInVuaXF1ZV9uYW1lIjoiYWRtaW5ARDM2NURlbW9UUzkwOTE5Ni5vbm1pY3Jvc29mdC5jb20iLCJ1cG4iOiJhZG1pbkBEMzY1RGVtb1RTOTA5MTk2Lm9ubWljcm9zb2Z0LQNvbSIsInV0aSI6Ii1oX1BmdWVySDAydlMzWkRDeEZ6QVEiLCJ2ZXIiOiIxLjAiLCJ3aWRzIjpbIjYyZTkwMzk0LTY5ZjUtNDIzNy05MTkwLTAxMjE3NzE0NWUxMCIsImI3OWZiZjRkLTNlZjktNDY4OS04MTQzLTc2YjE5NGU4NTUwOSJdfQ.B7-xfXv5UwPiYyrmbhpRlEOqOSs7aOranemqzFrAJx3h52D_tB2RjRj4rizuhKQTZ4XtyDcNZYMCmj57G64h2ICFXopm3dfpMmZ_hZ6qHD7zwRrQK2oQHUCpxtuyeT17ssLorFuWxZYfQYMxhjQYqu7WFWRX42IMBYeUqV7zGnnJmtMN1piaeasaSENVlo5IAxVyPfQyWv1roc-IjqNhxBB8Egnl3cez8sFDXY5JwwAcxpBRzHcF3HzLsQYqQ28bloUE44Za4JTR0tGushPl34AKdMblZYmCgysZiMH1Gyw8rYyJD2NeImV6Mo0cNvEnkS5tMzhDfMglHCSq92mjttQ",
"refresh_token": "0.AXwAP_KFHq_Azku7lpIBTTwTWYkU-FHuEp5Kqq6iWR9FmH18AAE.AgABAAEAAAD--DLA3VO7QrddgJg7WevrAgDs_wQA9P-jUK3eXBOWMvudf1yc-687D2O37fykNKvvoBi5VlWc0NLQCqKg-goiG6RGG66CFhyrBYHBscQN6tybyDbb3m9toQ7boa3gKqwqWYA2jUoQ1JFPr8SH1mebCy5RUPXCeGFrksWe1iFJfr-SFCWLh2wpBSRmiX0yZ02nbsDQNXZdNln7FVEcNvGzbFyzlqi-gIS-9FP6rSx82jcs1GJV2OxUkYIE0Bv6x2oPTtZYU78LuERPyxYQ4AxjQmpvzdWpVqidQ5UptW-QSgIpKq_jUFRUas9YZhJNCPNxN5BIUIVLMKFwxRWT3GA5GunjBK6BeUWRr_nI1wU_6G-A_bzxzbXCq5hZB1SsxrEQQDTaWvN8cjG5PPTSnXI6phmi38c-BI_zV2QxXuejPi4FPzWrSaWoru6R3HR7jBCMb6Amueyqks7Zuipbq3GkH-WWxQe26Y0echvDHm2_MkVaxDulQfesR25PFjvkzvFdOy9emLZFIOCmrNJK54gOnhcbn_kdDWQNEwzkOAtO1c6WK6mRKAkXnfObmTc0QsVkkC7YxY704B35ys-i8cYFJM69MDRcWbRg6M-Z4-cR3GCAsGi9_ZcdMXxnClQ-DefVYuc_dY-pWsH62DT92LF048ho1Nh2i3qhxcUWKGxk8ODukHeUNs5Z3504h7T1ssCwZQa65AERRT9ote2Rgi1U0NlOsz0STV9NGzktZK0iiDzLTtzCuEOw_JSr"
}

Altogether, your request and response should look like this:

The access_token property (beginning with "eyJ" and ending with "ttQ") is what we're after. We will supply this to all future requests.

We must supply this value as a Bearer Token, a specific format for providing an access token via an API. Open a new request in Postman. Go to the Authorization tab and change the Type dropdown to Bearer Token. Paste the value of the access_token into the token field:

Using Cookies from your Browser

When you are logged into a part of the Power Platform — say Power Apps, for example, a cookie will be added to your browsing session so you don’t have to re-authenticate on every page! We are actually able to “intercept” this cookie from the web browser and use this in our requests.

To get this cookie, we first need to know the URL of your Dataverse environment. From the Power Platform Admin Center, open your environment. Your will find this URL listed as the Environment URL. For example, mine looks like this: https://org56f8d45d.crm.dynamics.com/.

Append /api/data/v9.0/ to this environment URL, so it looks like this: https://org56f8d45d.crm.dynamics.com/api/data/v9.0/. From your authenticated browser session, navigate to this URL. You should receive a list of tables that exist in this environment.

Open your browser’s developer tools (I am using Microsoft Edge) with Ctrl+Shift+I. With the developer tools open, refresh the webpage. You should see a network log labeled v9.0. Click on this. In the headers tab (opened by default), scroll down to find the cookie header. Copy the value of this header; this is what we will be using!

In each request we make via Postman, we must provide this value in the headers, labeled as cookie. Open a new request in Postman. Add this value to the headers with the label cookie, like below:

The OData Protocol

The Dataverse API follows the standards described by the Open Data Protocol (“OData”). OData is a set of best practices for building and consuming RESTful API’s. Breaking this down, this means that the Dataverse API follows a standard that makes querying easy and understandable, with a format of which is almost universally understood. Some of the features of OData include:

  • $filter: filtering results
  • $select: selecting only specific fields to be returned
  • $orderby: sorting the returned results
  • $count: receiving a count of the queried records
  • $top: limiting the number of records returned Each of the parameters above can be passed into the query URL in a read request to the Dataverse API. For more information about OData: OData queries.

Dataverse Read Operation

Now that we have a request in Postman equipped with the necessary data to authenticate, we can begin making calls!

List Tables

Firstly, make a GET request (the drop down near the URL in Postman) to the following URL: https://org9442ae7b.crm.dynamics.com/api/data/v9.0 (obviously replacing org9442ae7b with your org name).

If successful, you will receive back a list of tables in your Dataverse instance, in JavaScript Object Notation (JSON) format. It will look like this (this is truncated, but you get the point):

{
"@odata.context": "https://org9442ae7b.crm.dynamics.com/api/data/v9.0/$metadata",
"value": [
{
"name": "accounts",
"kind": "EntitySet",
"url": "accounts"
},
{
"name": "contacts",
"kind": "EntitySet",
"url": "contacts"
},
{
"name": "phonecalls",
"kind": "EntitySet",
"url": "phonecalls"
},
...

In each object in the value property, we can see the name of the table, the type, and the url to access the data in the table.

Read records from a table

To get a list of records (data) that exist in each table, simply append one of the url properties to the URL that we used above to list the tables. For example, to get contacts: https://org9442ae7b.crm.dynamics.com/api/data/v9.0/contacts.

The response will return every field of every record in the contacts table. To limit the number of responses we get to 5, you can append $top=5 to the URL as a parameter, like so: https://org9442ae7b.crm.dynamics.com/api/data/v9.0/contacts?$top=5.

You just appended an OData parameter to your URL! By stacking the OData parameters mentioned earlier, you can create more complex queries.

Read a single record

If we know the GUID (“Global Unique Identifier”, a primary key) of a single record in a table, you can request data for only that record by including it in parentheses. For example, requesting a single record with ID 8e27ee97-cbe1-ec11-bb3d-00224803b8c6 from the contacts table: https://org9442ae7b.crm.dynamics.com/api/data/v9.0/contacts(8e27ee97-cbe1-ec11-bb3d-00224803b8c6). You will see that the response does not return an array of objects, but rather a single object.

Dataverse Write Operation

In addition to reading from Dataverse, we can also use the Web API for writing to Dataverse.

Create a New Record

Make a new request in Postman. Add the necessary authentication data, as described above in the Authenticate section. Set the HTTP method to POST and set your target URL to https://org9442ae7b.crm.dynamics.com/api/data/v9.0/accounts (obviously replacing org9442ae7b with your org name). This means our intention is to create a new account record.

Navigate to the Body column. Select raw as the body type, and JSON as the format. The Dataverse Web API accepts the data of the record in JSON format. To set the name of the account we would like to save, set the body to the following:

{
"name":"Stark Industries"
}

Hit send! If you receive a 204 No Content response, you have succeeded. Pull up the list of accounts in a model-driven app and now you should see your new account has been made.

Update a Record

As per the OData standard, we can only update a single record at a time via the Dataverse Web API. To do this, we must know the GUID (primary key) value of the record we wish to update. For example, changing the name of the account record with ID a33dd8e6-b6f0-ec11-bb3d-000d3a357ea4:

  • Set the HTTP method to PATCH
  • Set the URL to https://org9442ae7b.crm.dynamics.com/api/data/v9.0/accounts(a33dd8e6-b6f0-ec11-bb3d-000d3a357ea4) (obviously replacing org9442ae7b with your org name and a33dd8e6-b6f0-ec11-bb3d-000d3a357ea4 with a GUID of a record in your account table)
  • Similar to above, set the Body of your request to raw and the format to JSON with the following content:
{
"name":"Tesla Inc"
}

After sending this request, you will again receive a 204 No Content response if the update was successful. If you make a read call for the accounts table using the methods outlined earlier, you should see your change reflected.

Delete a Record

So far we’ve seen how to create a record, read a record, and update a record. Finally, we will explore how you can delete a record. Just like with update requests, the OData standard does not allow for deletion of multiple records in a single request. Thus, again, we must know the GUID of the record we would like to delete. For example, deletion of the account record with ID a33dd8e6-b6f0-ec11-bb3d-000d3a357ea4:

  • Set the HTTP method to DELETE
  • Set the URL to https://org9442ae7b.crm.dynamics.com/api/data/v9.0/accounts(a33dd8e6-b6f0-ec11-bb3d-000d3a357ea4) (obviously replacing org9442ae7b with your org name and a33dd8e6-b6f0-ec11-bb3d-000d3a357ea4 with a GUID of a record in your account table)
  • Note that this is the same URL that we used above for the update. The only difference between the update and delete operation is the HTTP method used.

Unlike the update operation, we obviously will not need to provide content in the request Body because this is merely a delete operation — no data should be changed. Be sure you have none selected under the Body tab.

After specifying the above in your request, press send. If you receive a 204 No Content response, this means your delete request was successful. The targeted record with the ID that you specified is now deleted.

Summary

There is a lot more to what the Dataverse Web API can provide, but I hope this tutorial was enough to get you started with using, but more importantly understanding the Dataverse Web API. The Dataverse Web API follows the OData standard, and thus, the more you learn about the OData protocol, the more capable you will be of working with the Dataverse Web API.

Written by Tim Hanewich, Business Applications Technical Specialist @ Microsoft (alias TIMH)

--

--