In this article, you will learn how to perform CRUD operations on Dataverse using the Web API in Power Pages.
Prerequisites
Before starting with the CRUD operations, make sure the following setup is completed:
Configure site settings for Web API access
Configure the required Dataverse tables.
Add appropriate table permissions.
Assign web roles to the site users.
Before moving to the implementation steps, these configurations must be in place. If you are new to this setup, refer to the step-by-step guide for configuring the Power Pages Web API for Dataverse integration. Read it here.
How Web API works in Power Pages
Power Pages provides a built-in Web API that allows you to interact with Dataverse tables using standard HTTP requests such as GET, POST, PATCH, and DELETE. This API runs in the context of the logged-in portal user, not as a system admin.
When a request is made from Power Pages, the platform checks:
Whether Web API access is enabled in site settings
Whether the user has the required web role
Whether the assigned table permissions allow the requested operation
If any of these checks fail, the request is blocked, even if the table exists in Dataverse.
Power Pages uses the /_api endpoint to communicate with Dataverse. Authentication and authorization are handled automatically, so you do not need to pass access tokens manually. This makes it secure and suitable for client side JavaScript usage.
Each Web API call maps directly to a Dataverse operation:
GET is used to read records
POST is used to create records
PATCH is used to update records
DELETE is used to remove records
Dataverse Tables used in this Demo
For this demo, i have used this Dataverse table named "Idea Requests" for storing and managing records from Power Pages. this table act as backend data source for all CRUD operations performed through the Web API.
![Screenshot 2025-12-13 194917]()
The table is enabled for Power Pages access and appropriate table permissions are configured to allow create, read, update, and delete operations.
Power Pages UI used in this demo
The user interface for this demo is built using HTML, CSS, and JavaScript in Power Pages. The top section of the page is designed as a gallery that displays existing records along with action buttons such as edit and delete.
Below the gallery, a custom form is provided to create and update records.
![Screenshot 2025-12-13 193504]()
Steps to create pages and make ready to code
1 - Create new subpage in site.
![Screenshot (1)]()
2 - Enter page name and select start from blank.
![Screenshot (5)]()
3 - After page is created, to edit code click on "Edit Code" (Visual Studio icon) as it will open in VS Code.
![Screenshot (3)]()
4 - Here you will see code of newly created page in VS Code.
![Screenshot (4)]()
Implementing CRUD operations using Web API
The complete code for this demo is available on GitHub. You can find the repository link at the end of this article.
Webapi ajax wrapper code
(function (webapi, $) {
function safeAjax(ajaxOptions) {
var deferredAjax = $.Deferred();
shell.getTokenDeferred().done(function (token) {
if (!ajaxOptions.headers) {
$.extend(ajaxOptions, {
headers: {
"__RequestVerificationToken": token
}
});
} else {
ajaxOptions.headers["__RequestVerificationToken"] = token;
}
$.ajax(ajaxOptions).done(function (data, textStatus, jqXHR) {
validateLoginSession(data, textStatus, jqXHR, deferredAjax.resolve);
}).fail(deferredAjax.reject);
}).fail(function () {
deferredAjax.rejectWith(this, arguments);
});
return deferredAjax.promise();
}
webapi.safeAjax = safeAjax;
})(window.webapi = window.webapi || {}, jQuery)
Explantation
This wrapper function is used to make secure Web API calls from Power Pages. Power Pages requires a request verification token for client side Web API requests, and this wrapper automatically handles that requirement.
The safeAjax function retrieves the security token using shell.getTokenDeferred() and attaches it to the request headers before making the AJAX call. This ensures that all Web API requests are authenticated and authorized correctly.
By centralizing this logic in a single wrapper, we avoid repeating token handling code for every CRUD operation. All create, read, update, and delete requests use this safeAjax method, making the code cleaner and easier to maintain.
In the next sections, this wrapper will be reused to perform CRUD operations on the Dataverse table using different HTTP methods.
Read Operation
function displayData() {
webapi.safeAjax({
type: "GET",
url: "/_api/cr097_idearequests",
contentType: "application/json",
success: function (res) {
allRecords = res?.value
console.log(res);
let tableBody = document.getElementById("records-body")
let tableData = ""
if (res?.value?.length > 0) {
res.value.forEach((item) => {
tableData +=
`
<tr id="record">
<td>${item.cr097_id}</td>
<td>${item.cr097_title ?? "N/A"}</td>
<td>${item.cr097_description ?? "N/A"}</td>
<td>${item["[email protected]"]}</td>
<td>
<button class="edit-btn" data-id="${item.cr097_idearequestid}">Edit</button>
<button class="delete-btn" data-id="${item.cr097_idearequestid}">Delete</button>
</td>
<tr>
`
})
tableBody.innerHTML = tableData
} else {
tableBody.innerHTML = "No records to display"
}
}
})
}
Explanation of key parameters:
type
url
In this example, /cr097_idearequests represents the entity set name of the Idea Request table.
contentType
success callback
How to get set name for Dataverse table
![Screenshot]()
Create Operation
function saveRecord() {
const record = {
cr097_title: title.value,
cr097_description: desc.value,
cr097_status: testStatus.value,
};
webapi.safeAjax({
type: "POST",
url: "/_api/cr097_idearequests",
contentType: "application/json",
data: JSON.stringify(record),
success: function (res) {
alert("Data saved");
displayData();
ideaRequestForm.reset();
submitBtn.textContent = "Save";
// location.refresh()
},
error: function (error) {
console.error("Failed to save record");
},
});
}
Explanation of key parameters:
record
type
url
data
Update Operation
function saveRecord() {
const record = {
cr097_title: title.value,
cr097_description: desc.value,
cr097_status: testStatus.value,
};
webapi.safeAjax({
type: "PATCH",
url: `/_api/cr097_idearequests(${editRecordId})`,
contentType: "application/json",
data: JSON.stringify(record),
success: function (res) {
alert("Data saved");
displayData();
ideaRequestForm.reset();
submitBtn.textContent = "Save";
// location.refresh()
},
error: function (error) {
console.error("Failed to save record");
},
});
}
Explanation of key parameters
type
url
editRecordId represents the unique identifier of the record being updated.
record
data
Delete Operation
function deleteRecord(id) {
console.log(id);
webapi.safeAjax({
type: "DELETE",
url: `/_api/cr097_idearequests(${id})`,
success: function (res) {
console.log("Deleted", res);
alert("Deleted");
location.reload();
},
error: function (error) {
console.error("Failed to delete", error);
},
});
}
Explanation of key parameters
type
url
id
Source Code
Conclusion
In this article, we explored how to perform CRUD operations on Dataverse using the Web API in Power Pages. Starting with the Dataverse table setup and the custom Power Pages UI, we implemented read, create, update, and delete operations using JavaScript and a Web API wrapper.