Gravity Forms Dynamics 365 integration overview
Gravity Forms Dynamics 365 integration: this guide shows how to connect Gravity Forms on WordPress to Microsoft Dynamics 365 CRM through the Dataverse Web API using OAuth 2.0 client credentials. You’ll authorize with a Dataverse Application User and build two feeds: a GET lookup that auto-fills form fields, and an optional POST that creates a lead when the form is submitted.
- A GET lookup that pulls CRM data into Gravity Forms fields (e.g., a contact by email or a custom table row by GUID).
- An optional POST that creates a lead in Dynamics 365 when the form is submitted.
Why this approach? Dataverse exposes an OData v4 Web API (stable, well-documented). Using the environment’s own endpoint (/api/data/v9.2/) keeps you close to the source of truth and avoids extra moving parts like external zaps.
Gravity Forms Dynamics 365 integration: prerequisites
- Gravity Forms + GravityWP API Connector plugin (WordPress): lets you configure OAuth 2.0 and map API responses into form fields no custom PHP.
- Microsoft Entra access: you need a registered app to request access tokens with client credentials.
- Power Platform access: you’ll grab the Environment URL and create a Dataverse Application User so the CRM enforces the right data permissions (security roles).
Step 1 Register an Entra app (OAuth 2.0 client credentials)
Why do this? OAuth 2.0 needs a confidential client (your WordPress site) that can prove its identity using a client ID and client secret, then request an access token for Dataverse. This is the standard server-to-server pattern for Dynamics 365/Dataverse.
- Entra admin center → Identity → Applications → App registrations → New registration.
Choose Accounts in this organizational directory only so the app stays within your tenant. - Copy from Overview: Application (client) ID and Directory (tenant) ID.
You’ll paste the client ID and tenant ID into the API Connector. - Certificates & secrets → New client secret.
Copy the secret Value immediately (it’s shown once); this becomes your client secret.




Step 2 Find your Dataverse Environment URL and build the Web API base
Why this host matters: Unlike Microsoft Graph, each Dataverse environment has its own organization URL and Web API endpoint. You must target your environment’s host so permissions, custom tables, and solutions are respected.
- Power Platform admin center → Environments → open your environment → copy Environment URL (e.g., yourorg.crm3.dynamics.com).
That crm number is your region/cluster; keep it.
Now derive two values:
- Scope (resource):
https://yourorg.crm3.dynamics.com/.default
Why? For confidential clients (server-to-server), Dataverse expects the .default scope for the environment resource; user_impersonation is for interactive (delegated) flows. - Web API base: https://yourorg.api.crm3.dynamics.com/api/data/v9.2/\
Why? The Web API path is always /api/data/, and the current version is v9.2. Using v9.2 keeps you aligned with docs and capabilities.

Step 3 Create a Dataverse Application User and assign a security role
Why not delegated permissions? Our WordPress integration runs server-side; there’s no human logging in at submission time. Dataverse authorizes app-to-app access using an Application User whose access is controlled by security roles (table-level privileges). This keeps everything least-privilege and auditable.
- Environment → Settings → Users + permissions → Application users → New app user.
- Choose your Entra app, then assign a role that includes:
- Read on tables you query (e.g., contact or your custom table).
- Create when you’ll write records (e.g., lead).
- Read on tables you query (e.g., contact or your custom table).
Step 4 Add the Dataverse connection in the GravityWP API Connector (WordPress)
Why these exact fields? They match how the Microsoft identity platform issues tokens for client credentials, and how Dataverse expects callers to scope requests to a specific environment.
- Base URL: https://yourorg.api.crm3.dynamics.com/api/data/v9.2/
(Web API path + v9.2 version the docs’ current release) - Auth: OAuth 2.0 → Client Credentials
- Token URL: https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token
(the v2.0 token endpoint for your tenant) - Scope: https://yourorg.crm3.dynamics.com/.default
(confidential client scope for Dataverse)
- Token URL: https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token
- Client ID / Client Secret: from Step 1.
Save.
Step 5 Make a small test form in Gravity Forms (so results are obvious)
Add Email (to test contacts), optional GUID (to test a custom table row), a Single Line Text field called Test Field (where we’ll write CRM data), and an optional Paragraph field called Raw JSON (to see the response during testing).
Why a text field target? The current alpha lets you map to Single Line Text and Paragraph Text. Use hidden text fields to store fetched values until the add-on supports typed targets like email/phone/select. (This avoids validation conflicts.)
Step 6 Gravity Forms Dynamics 365 integration GET lookup
Why GET first? Reads are safer and let you confirm your Base URL, scope, headers, and permissions before you start writing data.
Option A: Look up contacts by email (standard table)
- Endpoint URL: contacts
- Headers (recommended by Microsoft):
Accept: application/json · OData-Version: 4.0 · OData-MaxVersion: 4.0
Why? Dataverse only returns JSON and implements OData v4. Including these headers avoids ambiguity and caching gotchas. - Query string:
- $select = contactid,firstname,lastname,telephone1,emailaddress1
Why? $select returns only the columns you need, reducing payload and improving performance. - $filter = emailaddress1 eq ‘{Email:value}’
Why? Filters results server-side to the one person you care about. - $top = 1 + $orderby = modifiedon desc
Why? If duplicates exist, this gives you one deterministic row (the most recently modified). The docs show how to order and limit rows.
- $select = contactid,firstname,lastname,telephone1,emailaddress1
- Target mapping:
- Map Test Field → value/0/emailaddress1
- Map Test Field → value/0/emailaddress1
- (Optional) map value/0/firstname and value/0/lastname.
Why value/0/…? Dataverse returns query results in a value array following OData conventions; index 0 is the first row.
Option B: Look up a custom table row by GUID (mirrors your customer’s success)
- Endpoint URL: your table’s logical name (e.g., sts_inquiries).
- Headers: same as above.
- Query string: $filter = sts_inquiryid eq {GUID:FIELDID}
- If the server requires explicit types, use sts_inquiryid eq guid'{GUID:FIELDID}’.
- If the server requires explicit types, use sts_inquiryid eq guid'{GUID:FIELDID}’.
- Target mapping: Test Field → value/0/sts_email.
- (Optional) map Raw JSON → value/0 to inspect the entire row.

sts_email into a Gravity Forms field.Trigger choice (why it matters):
- On change, of any mapped field → instant form auto-fill during typing (great UX).
- On form submission → runs only server-side (cleaner logs, fewer requests).
Gravity Forms Dynamics 365 integration POST lead(Optional)
Why POST second? Once reads work, you can safely create records knowing auth and paths are correct.
- Endpoint URL: leads
- Headers: add Content-Type: application/json (required for JSON bodies).
- Body (example):
{ “subject”: “Website inquiry – {Email:value}”, “firstname”: “{First Name:3}”, “lastname”: “{Last Name:6}”, “emailaddress1”: “{Email:value}”, “telephone1”: “{Phone:4}” } - Trigger: On form submission → send entries to Dynamics to create a record in Dynamics (a lead).
Troubleshooting (root causes + reasons)
- 401 Unauthorized (invalid audience/scope):
Your Scope must target your environment host + /.default (e.g., https://yourorg.crm3.dynamics.com/.default). Microsoft’s guidance explicitly uses /.default for confidential clients. - 403 Forbidden (authZ):
The token is fine, but your Application User lacks privileges on that table. Assign or expand a security role in that environment (e.g., read contact, create lead). - 404 (logical name):
Use the logical table name (e.g., contacts, not “Contact”; custom tables often look like prefix_entities). Dataverse endpoints are per-environment, not global Graph. - OData query errors:
Strings must be in single quotes; some GUID filters require the guid’…’ literal. The Web API is OData v4, so it respects standard URL query options like $select, $filter, $orderby, $top. - Throttling (429):
Dataverse enforces Service Protection API limits; respect the Retry-After header to back off. A single lookup per submission is well within normal limits. - Nothing maps:
Open your browser’s Network panel, inspect the JSON, and adjust your mapping to the returned structure (e.g., value/0/emailaddress1). The docs also show how to select and limit columns for leaner payloads.
Why these exact URLs, headers, and query options?
- Base URL format: https://yourorg.api.crmX.dynamics.com/api/data/v9.2/
Microsoft defines /api/data/ and v9.2 as the current Web API path and version. Using the right cluster (e.g., crm3) makes sure you hit your environment. - Required headers:
Accept: application/json, OData-Version: 4.0, OData-MaxVersion: 4.0
Dataverse returns JSON only, and explicitly setting OData v4 guards you against future protocol changes. For POST/PUT/PATCH, add Content-Type: application/json. - .default scope:
For confidential clients (server-to-server), Microsoft’s guidance is to request the environment’s .default scope. Delegated user_impersonation applies to interactive user flows, not this one. - $select, $filter, $orderby, $top:
$select keeps responses small and fast; $filter narrows rows on the server; $orderby + $top=1 returns one deterministic record when duplicates exist. These are first-class OData v4 features; Microsoft’s samples recommend them.
Wrap-up (why this integration pays off)
This approach keeps your Gravity Forms to Dynamics 365 CRM connection simple, secure, and fast:
- Simple: The GravityWP API Connector add-on handles OAuth; you just paste IDs and URLs.
- Secure: Client credentials + Application User + security role = least-privilege, auditable access.
- Fast & reliable: Native Dataverse Web API calls (OData v4) with explicit headers and lightweight $select queries.
From here, you can connect Gravity Forms to more tables, integrate Gravity Forms with additional CRM processes, or expand the POST feed to create other records (cases, opportunities) based on form fields and user input without leaving WordPress.
Advanced Merge Tags
List Number Format
JWT Prefill
Advanced Number Field
Field to Entries
Update Multiple Entries
List Datepicker
List Text
API Connector
Entry to Database
n8n Connector