Dataverse quickstart & FAQ¶
This page is for integration partners building against akoyaGO and for internal akoyaGO developers writing against the platform. It curates the parts of Microsoft's Dataverse documentation that matter most for akoyaGO-style integrations, with akoyaGO-flavored examples.
Nothing here replicates Microsoft Learn. Every concept links to the authoritative Microsoft source. What's here is ordering, akoyaGO context, and the specific gotchas foundation-platform partners hit.
What is Dataverse?¶
Dataverse is Microsoft's low-code data platform — the same storage and API layer that backs Dynamics 365. akoyaGO tables live in a Dataverse environment, reachable through a REST/OData Web API and an older SOAP Organization Service. Partners should use the Web API unless building in-process plugins.
See also: What is Dataverse? — Microsoft Learn.
Before you start¶
You need three things:
- Credentials — see Authentication.
- An environment URL —
https://{org}.crm.dynamics.com. Your foundation admin or GOsupport will tell you which{org}to use. - An HTTP client — examples below show the same call in raw HTTP, curl, Python (
requests), and C# (ServiceClient). Use whichever fits your stack.
Examples conventions
Examples below assume ORG (the environment URL), access_token (a valid bearer token), headers (a standard Dataverse headers dict — Authorization, Accept, OData-Version, OData-MaxVersion), and service (a ServiceClient instance). The first example below shows how to set these up; later examples reference them directly.
Your first five minutes¶
1. Know the Web API endpoint pattern¶
Every Dataverse request shares a base URL:
Each table has a plural entity set name appended — akoya_gifts, akoya_funds, contacts. A single record is addressed by its GUID in parentheses: akoya_gifts({giftid}).
See also: Web API reference — Microsoft Learn.
In akoyaGO: the Web API section at the top of every entity reference page gives the exact endpoint for that table.
2. Authenticate¶
Acquire a Bearer token via Entra ID OAuth 2.0 (see Authentication). Pass it as Authorization: Bearer {token} on every request.
3. Make your first GET — five funds¶
import requests
ORG = "https://{org}.crm.dynamics.com"
access_token = "eyJ0eXAi..." # from the token endpoint
headers = {
"Authorization": f"Bearer {access_token}",
"Accept": "application/json",
"OData-Version": "4.0",
"OData-MaxVersion": "4.0",
}
r = requests.get(
f"{ORG}/api/data/v9.2/akoya_funds",
params={"$top": 5, "$select": "akoya_fundname,akoya_fundcode"},
headers=headers,
)
r.raise_for_status()
for fund in r.json()["value"]:
print(fund["akoya_fundname"])
// service is a ServiceClient instance from Microsoft.PowerPlatform.Dataverse.Client
var query = new QueryExpression("akoya_fund") {
ColumnSet = new ColumnSet("akoya_fundname", "akoya_fundcode"),
TopCount = 5
};
var funds = service.RetrieveMultiple(query);
foreach (var f in funds.Entities)
Console.WriteLine(f.GetAttributeValue<string>("akoya_fundname"));
4. Narrow the payload with $select¶
Dataverse returns every column by default. Always pass $select — it reduces payload size, improves response time, and avoids accidentally depending on columns that may change.
See also: Query data using the Web API — Microsoft Learn.
5. Follow lookups with $expand¶
Lookups aren't populated in the response by default — you get a raw _xxx_value GUID field. To pull related data inline, use $expand with the navigation property name (PascalCase, not the lowercase logical name).
curl "https://{org}.crm.dynamics.com/api/data/v9.2/akoya_funds?\$select=akoya_fundname&\$expand=akoya_PrimaryDonor(\$select=akoya_formaldefault),akoya_GiftDefaultAccount(\$select=akoya_accountnum)" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Accept: application/json" \
-H "OData-Version: 4.0" \
-H "OData-MaxVersion: 4.0"
// ServiceClient — use LinkEntity for joins, or a follow-up Retrieve via EntityReference
var query = new QueryExpression("akoya_fund") {
ColumnSet = new ColumnSet("akoya_fundname", "akoya_primarydonor", "akoya_giftdefaultaccount")
};
query.LinkEntities.Add(new LinkEntity {
LinkFromEntityName = "akoya_fund",
LinkFromAttributeName = "akoya_primarydonor",
LinkToEntityName = "akoya_donor",
LinkToAttributeName = "akoya_donorid",
Columns = new ColumnSet("akoya_formaldefault"),
EntityAlias = "donor",
JoinOperator = JoinOperator.LeftOuter
});
var funds = service.RetrieveMultiple(query);
The navigation property name is PascalCase (akoya_PrimaryDonor), not lowercase. The Lookups — quick reference table on every entity reference page lists both.
See also: Retrieve related records — Microsoft Learn.
Common query patterns¶
| Pattern | Query option | Microsoft Learn |
|---|---|---|
| Filter | $filter=akoya_endowed eq true |
Filter results |
| Sort | $orderby=akoya_fundname asc |
Order rows |
| Page size | $top=50 (max 5000 per request) |
Specify number of rows |
| Paginate | Follow @odata.nextLink in the response |
Page results |
| Count only | /$count or $count=true |
Count rows |
| Fetch by ID | akoya_funds({fundid}) |
Retrieve a record |
Client libraries and tools¶
There's no single "right" way to talk to Dataverse. Pick what fits your stack.
| Option | Typical use | Notes |
|---|---|---|
| curl / HTTPie | Command-line exploration, CI scripts | Zero dependencies. Pair with jq for parsing. |
| Postman / Bruno | GUI exploration, partner handoff | Save a collection of akoyaGO requests and share it. |
Python — requests + msal |
ETL, scripts, Python-stack integrations | msal handles token acquisition; requests is idiomatic HTTP. |
Dataverse .NET SDK (Microsoft.PowerPlatform.Dataverse.Client) |
C# / .NET apps, Dataverse plugins | ServiceClient wraps auth + retry + batching; QueryExpression for typed queries. Required for writing plugins. |
| Node.js / TypeScript | JavaScript-stack integrations | No official SDK; MSAL + fetch works. Community packages exist. |
| XrmToolBox | Admin-side inspection, schema exploration | Windows-only. Indispensable for tracing integration issues. |
Frequently asked questions¶
Web API basics¶
Q: What's the base URL?
https://{org}.crm.dynamics.com/api/data/v9.2/. Replace {org} with your environment's subdomain.
Q: What API version should I target?
v9.2. It's the current stable Web API version. Older (v9.0, v9.1) still work, but newer features ship only in 9.2.
Q: Which headers do I need?
At minimum: Authorization: Bearer {token}, Accept: application/json, OData-Version: 4.0, OData-MaxVersion: 4.0. For writes, add Content-Type: application/json. For conditional updates, add If-Match: *.
Q: What's OData v4?
A query protocol Microsoft built on top of HTTP. It defines query options ($filter, $select, $expand, $orderby, etc.) that Dataverse exposes. See also: OData documentation.
Schema terminology¶
Q: Logical name, schema name, entity set name, navigation property — what's what?
| Term | Example (Gift) | When to use |
|---|---|---|
| Logical name | akoya_gift |
In XML, C# SDK, and attribute references in $filter. Lowercase. |
| Schema name | akoya_Gift |
Rarely needed at runtime; used in customization XML. |
| Entity set name | akoya_gifts |
In the Web API URL path. |
| Primary ID attribute | akoya_giftid |
Primary-key column name. |
| Navigation property | akoya_Donor, akoya_Fund1 |
In $expand and @odata.bind. PascalCase. |
See also: Entity metadata overview — Microsoft Learn.
Q: What's @odata.bind and when do I need it?
Use @odata.bind on writes to set a lookup column. You bind a record URL rather than a raw GUID:
See also: Associate and disassociate entities — Microsoft Learn.
Q: Why is _xxx_value different from the navigation property?
On reads, Dataverse returns lookups as _akoya_donor_value (lowercase, underscore-wrapped) — the raw GUID of the related record. The navigation property (akoya_Donor, PascalCase) is what you use in $expand to pull the related record inline. Every entity reference page lists both.
Data patterns¶
Q: How do I upsert in akoyaGO?
akoyaGO tables don't have alternate keys configured, so standard upsert syntax (PATCH /akoya_funds(akoya_fundcode='F-001234')) won't work. Use lookup then PATCH — query by the business identifier first, then PATCH by GUID. See the find-by-code example and the Find then update scenario on any entity reference page.
Q: What are _Base currency fields?
Every money column has a system-maintained _Base sibling that holds the value in the organization's base currency. akoya_totalgift is in the transaction currency (transactioncurrencyid); akoya_totalgift_base is the converted value. Never write to _Base columns directly — they're system-calculated.
Q: How do I query a solution-specific entity vs a standard one?
The same way. Logical names tell you which is which — akoyaGO customs start with akoya_, standards (contact, account, list) don't. There's no URL or query-option difference.
Q: How do I do incremental sync?
Dataverse supports change tracking — a delta-query mechanism. On entities with change tracking enabled, Dataverse returns an @odata.deltaLink URL you can follow for subsequent incremental pulls. All documented akoyaGO entities have change tracking enabled except akoya_CriteriaList.
See also: Use change tracking to synchronize data — Microsoft Learn.
Production concerns¶
Q: What are the rate limits?
Dataverse enforces per-user service-protection limits: 6000 API requests per 5-minute rolling window per app user / connection identity, with concurrency caps. Exceeding yields 429 Too Many Requests with a Retry-After header.
See also: Service protection API limits — Microsoft Learn.
Q: How do I handle 429?
Respect Retry-After. Back off exponentially on repeated failures. Never ignore a 429 — repeated hits lead to longer cool-downs.
Q: How do I do bulk writes?
Use the $batch endpoint. One HTTP request wraps many operations and can be transactional (all-or-nothing per change set). Batch is the right choice for creating large numbers of records or making many related updates.
See also: Execute batch operations — Microsoft Learn.
Q: How do I act on behalf of a specific user?
Pass the MSCRMCallerID request header with the user's system user ID. The request then runs under that user's security context, provided your app has impersonation rights.
See also: Impersonate another user — Microsoft Learn.
Debugging¶
Q: Best tool for testing queries without writing code?
Postman or Bruno for REST. XrmToolBox has excellent plugins (FetchXML Builder, Plugin Trace Viewer) for schema exploration and plugin debugging. FetchXML queries can be translated to OData through fetchxmlbuilder.com.
Q: How do I trace a failing request?
Dataverse returns structured JSON error responses on 4xx / 5xx. Inspect error.message and error.innererror.trace — the trace often names the exact plugin, workflow, or business rule that rejected the request.
See also: Compose HTTP requests and handle errors — Microsoft Learn.
What's next¶
- Authentication — full credential and security-role guide.
- Entity reference — every documented akoyaGO table with Web API endpoints and examples.
- The constituent model — how
contact,account, andakoya_donorrelate. - Query funds — realistic fund-query scenarios: pagination, hierarchy, find-by-code.
- Create a contact and link to a donor — end-to-end constituent creation with
@odata.bind.