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:

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:

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:

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.