Power Pages Web API

Quick Reference Guide for CRUD Operations & Query Options

📖 Read Operations

GET Basic Read
Retrieve all records from a table using webapi.safeAjax()
webapi.safeAjax({ type: "GET", url: "/_api/accounts", contentType: "application/json", success: function(data) { console.log("Records:", data.value); data.value.forEach(function(record) { console.log(record.name); }); } });
GET $select - Select Specific Fields
Return only specified properties to improve performance
/_api/accounts?$select=name,revenue
GET $filter - Filter Results
Apply filtering criteria using OData operators (eq, ne, gt, lt, and, or)
/_api/accounts?$filter=revenue gt 90000
GET $orderby - Sort Results
Sort results ascending or descending
/_api/accounts?$orderby=revenue desc
GET $top - Limit Records
Limit the number of records returned
/_api/accounts?$top=10
GET $expand - Include Related Records
Retrieve related records via navigation properties
/_api/accounts?$expand=contact_customer
GET $count - Get Record Count
Return total count of records
/_api/accounts?$count=true
GET String Functions
Use contains(), startswith(), endswith() for text filtering
/_api/accounts?$filter=contains(name,'Contoso')
GET Combine Query Options
Chain multiple query options with &
/_api/accounts?$select=name&$filter=revenue gt 1000&$orderby=name&$top=5

✏️ Write Operations

POST Create Record
Create new record with JSON payload using webapi.safeAjax()
webapi.safeAjax({ type: "POST", url: "/_api/accounts", contentType: "application/json", data: JSON.stringify({ "name": "Sample Account", "revenue": 50000 }), success: function(data) { console.log("Record created:", data.accountid); } });
PATCH Update Record
Update existing record by ID using webapi.safeAjax()
webapi.safeAjax({ type: "PATCH", url: "/_api/accounts(record-id)", contentType: "application/json", data: JSON.stringify({ "name": "Updated Name", "revenue": 100000 }), success: function(data) { console.log("Record updated"); } });
DELETE Delete Record
Delete record by ID using webapi.safeAjax()
webapi.safeAjax({ type: "DELETE", url: "/_api/accounts(record-id)", success: function() { console.log("Record deleted"); }, error: function(error) { console.error("Delete failed:", error); } });

🛠️ Helper Function

Generic Web API Function
Reusable function that accepts parameters for any Web API operation
function callWebAPI(method, entitySet, recordId, data, queryString) { var url = "/_api/" + entitySet; if (recordId) url += "(" + recordId + ")"; if (queryString) url += "?" + queryString; webapi.safeAjax({ type: method, url: url, contentType: "application/json", data: data ? JSON.stringify(data) : null, success: function(result) { console.log("Success:", result); return result; }, error: function(error) { console.error("Error:", error); } }); } // Usage Examples: callWebAPI("GET", "accounts", null, null, "$select=name&$top=5"); callWebAPI("POST", "accounts", null, {name: "New Account"}); callWebAPI("PATCH", "accounts", "record-id", {name: "Updated"}); callWebAPI("DELETE", "accounts", "record-id");

🔗 Dataverse Relationships

GET 1:N - Read Related Records
One-to-Many: Use $expand to retrieve child records (e.g., Account → Contacts)
webapi.safeAjax({ type: "GET", url: "/_api/accounts(account-id)?$expand=contact_customer_accounts", success: function(data) { console.log("Child contacts:", data.contact_customer_accounts); } });
GET N:1 - Read Parent Record
Many-to-One: Use $expand to retrieve parent record (e.g., Contact → Account)
webapi.safeAjax({ type: "GET", url: "/_api/contacts(contact-id)?$expand=parentcustomerid_account", success: function(data) { console.log("Parent account:", data.parentcustomerid_account); } });
POST Create with N:1 Lookup
Create child record and link to parent using lookup field binding
webapi.safeAjax({ type: "POST", url: "/_api/contacts", contentType: "application/json", data: JSON.stringify({ "firstname": "John", "lastname": "Doe", "parentcustomerid_account@odata.bind": "/accounts(account-id)" }) });
PATCH Update N:1 Relationship (Method 1)
Update lookup using @odata.bind annotation in PATCH request
webapi.safeAjax({ type: "PATCH", url: "/_api/contacts(contact-id)", contentType: "application/json", data: JSON.stringify({ "parentcustomerid_account@odata.bind": "/accounts(new-account-id)" }) });
PUT Update N:1 Relationship (Method 2)
Change reference using PUT on $ref endpoint with @odata.id
webapi.safeAjax({ type: "PUT", url: "/_api/contacts(contact-id)/parentcustomerid_account/$ref", contentType: "application/json", data: JSON.stringify({ "@odata.id": "/_api/accounts(new-account-id)" }) });
DELETE Remove N:1 Lookup (Disassociate)
Remove single-valued navigation property reference using DELETE on $ref endpoint
webapi.safeAjax({ type: "DELETE", url: "/_api/contacts(contact-id)/parentcustomerid_account/$ref", success: function() { console.log("Lookup cleared"); } });
GET N:N - Read Many-to-Many
Many-to-Many: Use $expand with relationship collection (e.g., Contact → Marketing Lists)
webapi.safeAjax({ type: "GET", url: "/_api/contacts(contact-id)?$expand=listmember_association", success: function(data) { console.log("Marketing lists:", data.listmember_association); } });
POST N:N - Associate Records
Create Many-to-Many relationship using $ref endpoint
webapi.safeAjax({ type: "POST", url: "/_api/contacts(contact-id)/listmember_association/$ref", contentType: "application/json", data: JSON.stringify({ "@odata.id": "/_api/lists(list-id)" }) });
DELETE N:N - Disassociate Records
Remove Many-to-Many relationship using $ref with $id query parameter
webapi.safeAjax({ type: "DELETE", url: "/_api/contacts(contact-id)/listmember_association/$ref?$id=/_api/lists(list-id)", success: function() { console.log("Relationship removed"); } });
Navigation Property Names
Find relationship names in Power Pages Design Studio or using $metadata endpoint
/_api/$metadata // Look for NavigationProperty elements // Example: contact_customer_accounts

🔐 Security & Configuration

Table Permissions Required
Web API respects table permissions. Configure via Portal Management → Table Permissions + Web Roles
Users can only access data authorized by their web role
Enable Web API per Table
Must enable in site settings for each table
Webapi/<tablename>/enabled = true
Webapi/<tablename>/fields = name,email,phone
CSRF Token Required
Write operations require CSRF token for security. Use webapi.safeAjax()
webapi.safeAjax({
type: "POST",
url: "/_api/accounts",
data: JSON.stringify({name: "Test"})
})
⬇️ Download PDF