Skip to content

Contact (contact)

contact is the standard Dataverse table for individual people. akoyaGO uses it directly — staff, donors, grant applicants, scholarship recipients, board members, and volunteers are all contact records. akoyaGO extends contact with custom columns under the akoya_ prefix and wires it into donor, gift, and request workflows.

For the full schema of the base contact entity, see the Microsoft Dataverse contact reference. This page focuses on what's specific to akoyaGO and what integration partners need to know.

At a glance

Display name Contact
Logical name contact
Primary ID attribute contactid
Primary name attribute fullname (computed from firstname + lastname)
Entity set name (Web API) contacts
Ownership UserOwned
Change tracking Enabled (standard)
Audit Enabled (standard)

Web API

GET  {org}/api/data/v9.2/contacts
GET  {org}/api/data/v9.2/contacts({contactid})
POST {org}/api/data/v9.2/contacts
PATCH {org}/api/data/v9.2/contacts({contactid})

The akoyaGO role of contact

Every physical person in akoyaGO is a contact. That person may also be linked from one or more of:

  • akoya_donor — via akoya_primarycontact and/or akoya_secondarycontact lookups (see the constituent model).
  • akoya_request — via akoya_applicantid (required on grant/scholarship requests).
  • akoya_gift — via akoya_primarydonorcontact, akoya_secondarydonorcontact, akoya_payor, and akoya_memorialcontact lookups.
  • akoya_fund — via akoya_primaryfundcontact and fund advisor relationships.

One contact can participate in many of these roles simultaneously.

Notable akoyaGO-added columns

akoyaGO extends contact with columns under the akoya_ prefix. The columns most relevant to integration partners:

Display name Logical name Type Purpose
Active Address akoya_activeaddress Choice Which of the multi-address slots (home, business, seasonal) is currently active.
Spouse Email akoya_spouseemail String Spouse's email when the contact is part of a two-person household donor.
GOdonate Email Confirmed akoya_godonateemailconfirmed Boolean Set when the contact has confirmed an email via the GOdonate portal. Not an authoritative email-marketing opt-in flag — see the note below.

Email-marketing consent — known gap

akoya_godonateemailconfirmed captures one specific portal confirmation, not general email-marketing consent. There is no authoritative email-preference / opt-in-date column on contact today. Integrations needing reliable consent state should coordinate with the akoyaGO product team before building. Tracked as a schema gap in the project implementation plan.

Standard columns most used in integrations

From the base contact entity, partners typically read:

Logical name Type Notes
firstname String
lastname String
fullname String (computed) Concatenation — don't write directly.
emailaddress1 String Primary email. Use this for email-marketing / audience sync.
emailaddress2 / emailaddress3 String Secondary / tertiary.
mobilephone String
telephone1 String Primary phone.
address1_line1 / _line2 / _city / _stateorprovince / _postalcode / _country String Primary mailing address.
birthdate DateTime (DateOnly)
statecode / statuscode Choice Active / Inactive lifecycle.

Lookups from contact to akoyaGO entities

contact is usually the referenced side, not the referencing side. To find the donor records that reference a contact:

GET {org}/api/data/v9.2/akoya_donors?$select=akoya_donorid,akoya_formaldefault&$filter=_akoya_primarycontact_value eq {contactid} or _akoya_secondarycontact_value eq {contactid}
Accept: application/json
OData-Version: 4.0
OData-MaxVersion: 4.0
curl "https://{org}.crm.dynamics.com/api/data/v9.2/akoya_donors?\$select=akoya_donorid,akoya_formaldefault&\$filter=_akoya_primarycontact_value%20eq%20$CONTACT_ID%20or%20_akoya_secondarycontact_value%20eq%20$CONTACT_ID" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Accept: application/json" \
  -H "OData-Version: 4.0" \
  -H "OData-MaxVersion: 4.0"
contact_id = "..."
r = requests.get(
    f"{ORG}/api/data/v9.2/akoya_donors",
    params={
        "$select": "akoya_donorid,akoya_formaldefault",
        "$filter": f"_akoya_primarycontact_value eq {contact_id} or _akoya_secondarycontact_value eq {contact_id}",
    },
    headers=headers,
)
donors = r.json()["value"]
var contactId = new Guid("...");
var query = new QueryExpression("akoya_donor") {
    ColumnSet = new ColumnSet("akoya_donorid", "akoya_formaldefault"),
    Criteria = {
        FilterOperator = LogicalOperator.Or,
        Conditions = {
            new ConditionExpression("akoya_primarycontact", ConditionOperator.Equal, contactId),
            new ConditionExpression("akoya_secondarycontact", ConditionOperator.Equal, contactId)
        }
    }
};
var donors = service.RetrieveMultiple(query);

Supported messages

Message Supported
Create
Retrieve
RetrieveMultiple
Update
Delete
Upsert — (no akoyaGO alternate keys; use GET then PATCH)

Examples

Conventions

Examples assume ORG (env URL), access_token (valid bearer), headers (standard Dataverse headers dict), and service (a ServiceClient instance). See Authentication.

Find a contact by email

GET {org}/api/data/v9.2/contacts?
  $select=contactid,fullname,emailaddress1,akoya_godonateemailconfirmed&
  $filter=emailaddress1 eq 'donor@example.org'&
  $top=1
Accept: application/json
OData-Version: 4.0
OData-MaxVersion: 4.0
curl "https://{org}.crm.dynamics.com/api/data/v9.2/contacts?\$select=contactid,fullname,emailaddress1,akoya_godonateemailconfirmed&\$filter=emailaddress1%20eq%20'donor@example.org'&\$top=1" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Accept: application/json" \
  -H "OData-Version: 4.0" \
  -H "OData-MaxVersion: 4.0"
r = requests.get(
    f"{ORG}/api/data/v9.2/contacts",
    params={
        "$select": "contactid,fullname,emailaddress1,akoya_godonateemailconfirmed",
        "$filter": "emailaddress1 eq 'donor@example.org'",
        "$top": 1,
    },
    headers=headers,
)
hits = r.json()["value"]
contact = hits[0] if hits else None
var query = new QueryExpression("contact") {
    ColumnSet = new ColumnSet("fullname", "emailaddress1", "akoya_godonateemailconfirmed"),
    Criteria = {
        Conditions = {
            new ConditionExpression("emailaddress1", ConditionOperator.Equal, "donor@example.org")
        }
    },
    TopCount = 1
};
var result = service.RetrieveMultiple(query);
var contact = result.Entities.FirstOrDefault();

Email-marketing audience sync query

Active contacts with a confirmed portal email, ready for an audience push to an external email-marketing platform. Pair with @odata.deltaLink for incremental delta sync.

GET {org}/api/data/v9.2/contacts?
  $select=contactid,firstname,lastname,emailaddress1,akoya_godonateemailconfirmed&
  $filter=statecode eq 0 and akoya_godonateemailconfirmed eq true and emailaddress1 ne null&
  $orderby=modifiedon asc
Accept: application/json
OData-Version: 4.0
OData-MaxVersion: 4.0
Prefer: odata.track-changes
curl "https://{org}.crm.dynamics.com/api/data/v9.2/contacts?\$select=contactid,firstname,lastname,emailaddress1,akoya_godonateemailconfirmed&\$filter=statecode%20eq%200%20and%20akoya_godonateemailconfirmed%20eq%20true%20and%20emailaddress1%20ne%20null&\$orderby=modifiedon%20asc" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Accept: application/json" \
  -H "OData-Version: 4.0" \
  -H "OData-MaxVersion: 4.0" \
  -H "Prefer: odata.track-changes"
r = requests.get(
    f"{ORG}/api/data/v9.2/contacts",
    params={
        "$select": "contactid,firstname,lastname,emailaddress1,akoya_godonateemailconfirmed",
        "$filter": "statecode eq 0 and akoya_godonateemailconfirmed eq true and emailaddress1 ne null",
        "$orderby": "modifiedon asc",
    },
    headers={**headers, "Prefer": "odata.track-changes"},
)
body = r.json()
contacts = body["value"]
delta_link = body.get("@odata.deltaLink")  # persist for the next incremental call
var query = new QueryExpression("contact") {
    ColumnSet = new ColumnSet("firstname", "lastname", "emailaddress1", "akoya_godonateemailconfirmed"),
    Criteria = {
        Conditions = {
            new ConditionExpression("statecode", ConditionOperator.Equal, 0),
            new ConditionExpression("akoya_godonateemailconfirmed", ConditionOperator.Equal, true),
            new ConditionExpression("emailaddress1", ConditionOperator.NotNull)
        }
    },
    Orders = { new OrderExpression("modifiedon", OrderType.Ascending) }
};
var contacts = service.RetrieveMultiple(query);
// For incremental delta sync, use RetrieveEntityChangesRequest instead.

Two-step: POST the contact, then PATCH the donor's primary-contact lookup.

POST {org}/api/data/v9.2/contacts
Accept: application/json
OData-Version: 4.0
OData-MaxVersion: 4.0
Content-Type: application/json

{
  "firstname": "Jane",
  "lastname": "Smith",
  "emailaddress1": "jane.smith@example.org"
}

Then:

PATCH {org}/api/data/v9.2/akoya_donors({donorid})
Content-Type: application/json
If-Match: *

{
  "akoya_PrimaryContact@odata.bind": "/contacts({contactid})"
}
CONTACT_RESP=$(curl -s -i -X POST "https://{org}.crm.dynamics.com/api/data/v9.2/contacts" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "OData-MaxVersion: 4.0" \
  -H "OData-Version: 4.0" \
  -d '{
    "firstname": "Jane",
    "lastname": "Smith",
    "emailaddress1": "jane.smith@example.org"
  }')
CONTACT_ID=$(echo "$CONTACT_RESP" | grep -i '^OData-EntityId' | sed -E 's/.*\(([^)]+)\).*/\1/' | tr -d '\r')

curl -X PATCH "https://{org}.crm.dynamics.com/api/data/v9.2/akoya_donors({donorid})" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "If-Match: *" \
  -d "{\"akoya_PrimaryContact@odata.bind\": \"/contacts($CONTACT_ID)\"}"
r = requests.post(
    f"{ORG}/api/data/v9.2/contacts",
    json={
        "firstname": "Jane",
        "lastname": "Smith",
        "emailaddress1": "jane.smith@example.org",
    },
    headers={**headers, "Content-Type": "application/json"},
)
# OData-EntityId header contains the new contact URL — extract the GUID.
contact_id = r.headers["OData-EntityId"].rsplit("(", 1)[1].rstrip(")")

requests.patch(
    f"{ORG}/api/data/v9.2/akoya_donors({donor_id})",
    json={"akoya_PrimaryContact@odata.bind": f"/contacts({contact_id})"},
    headers={**headers, "Content-Type": "application/json", "If-Match": "*"},
)
var contact = new Entity("contact");
contact["firstname"] = "Jane";
contact["lastname"] = "Smith";
contact["emailaddress1"] = "jane.smith@example.org";
var contactId = service.Create(contact);

var donor = new Entity("akoya_donor", donorId);
donor["akoya_primarycontact"] = new EntityReference("contact", contactId);
service.Update(donor);

Change history

akoyaGO-specific extension columns extracted from the Akoyanet solution on 2026-04-24. Base contact columns are not listed here — partners should reference Microsoft's Dataverse documentation for those.