Appearance
People and organizations
Paging, updated_since, the deleted short form and the /ids endpoints work as described in Paging and Keeping a copy in sync. This page covers only what is specific to each resource.
People
A person is a contact in the workspace: a member, a customer contact, an instructor or anyone else Engagifii holds a record for. Inactive people are included with "status": "inactive". A person's id is the person_id used on registrations, invoices and payments.
| Endpoint | Meaning |
|---|---|
GET /people | List people, one page at a time. |
GET /people/ids | The id of every person that has not been deleted. |
GET /people/{id} | One person. 404 if the person does not exist or has been deleted. |
Filters
| Parameter | Type | Meaning |
|---|---|---|
organization_id | UUID | Only people whose primary organization is this one. |
status | string | active or inactive. |
Example
json
{
"id": "3f0c…",
"salutation": "Ms.",
"first_name": "Dana",
"middle_name": null,
"last_name": "Whitfield",
"suffix": null,
"pid": "100482",
"title": "Director of Programs",
"email": "dana.whitfield@example.org",
"phone": "555-0142",
"primary_organization_id": "9b21…",
"status": "active",
"time_zone": "Eastern Standard Time",
"is_instructor": false,
"date_of_birth": "1979-05-14",
"gender": "female",
"race": "Prefer not to say",
"ethnicity": null,
"emails": [
{ "email": "dana.whitfield@example.org", "type": "Work Email", "is_primary": true }
],
"phones": [
{ "phone": "555-0142", "type": "Work Phone", "is_primary": true }
],
"addresses": [
{
"type": "Mailing Address",
"line_1": "100 Main Street",
"line_2": "Suite 4",
"city": "Springfield",
"state": "IL",
"postal_code": "62701",
"country": "United States",
"is_billing": true
}
],
"positions": [
{
"id": "c47e…",
"organization_id": "9b21…",
"position": { "id": "5d10…", "name": "Director" },
"department": { "id": "e2a8…", "name": "Programs" },
"is_current": true,
"is_future": false,
"start_date": "2022-03-01",
"end_date": null,
"terms": [
{
"id": "b6e2…",
"name": "2024-2026 Term",
"scenario": "elected",
"region": { "id": "0f3a…", "name": "District 4" },
"start_date": "2024-07-01",
"end_date": "2026-06-30"
}
]
}
],
"organizations": [
{ "organization_id": "9b21…", "is_contact_person": true }
],
"member_types": [ { "id": "71f3…", "name": "Individual Member" } ],
"member_type_history": [
{ "member_type_id": "71f3…", "name": "Individual Member", "start_date": "2021-01-01", "end_date": null, "is_current": true },
{ "member_type_id": "71f4…", "name": "Associate Member", "start_date": "2019-01-01", "end_date": "2020-12-31", "is_current": false }
],
"tags": ["Board", "Volunteer"],
"custom_fields": [
{ "field_id": "a90d…", "name": "Member Since", "group": "Membership", "type": "date", "value": "2015-06-01" }
],
"email_opt_outs": [
{ "email": "dana.whitfield@example.org", "group_id": "4e7a…", "opted_out_at": "2026-03-02T16:40:12Z" }
],
"last_login_at": "2026-10-28T14:02:51Z",
"created_at": "2015-06-01T12:00:00Z",
"updated_at": "2026-10-30T09:15:22Z"
}Fields
| Field | Type | Meaning |
|---|---|---|
id | UUID | The person's id. |
salutation | string or null | For example Ms. or Dr. |
first_name | string or null | |
middle_name | string or null | |
last_name | string or null | |
suffix | string or null | For example Jr. |
pid | string or null | The person ID Engagifii shows in the profile header. Workspaces often use it as the member number in other systems. |
title | string or null | The person's job title. |
email | string or null | The person's main email address. |
phone | string or null | The person's main phone number. |
primary_organization_id | UUID or null | The person's primary organization. An id from /organizations. |
status | string | active or inactive. |
time_zone | string or null | The person's time zone as stored in Engagifii, for example Eastern Standard Time. |
is_instructor | boolean | Whether the person is an instructor. |
date_of_birth | date or null | The date of birth from the person's standard profile (Personal Details). null if none is entered. |
gender | string or null | The gender from the standard profile: male, female or not_specified. null if none is entered. |
race | string or null | The race from the standard profile, as the label in the workspace's own list of options. null if none is chosen. |
ethnicity | boolean or null | The yes/no ethnicity answer from the standard profile. null if it was never answered. |
emails | array | Every email address on the person. See Emails, phones and addresses. |
phones | array | Every phone number on the person. |
addresses | array | Every address on the person. |
positions | array | The person's positions at organizations, past, current and future. Current positions come first, then the most recent start date. |
positions[].id | UUID | The position record's id. |
positions[].organization_id | UUID or null | The organization the position is at. |
positions[].position | object or null | The position held. null if none is set. |
positions[].position.id | UUID | The position's id. |
positions[].position.name | string or null | The position's name, for example Director. |
positions[].department | object or null | The department. null if none is set. |
positions[].department.id | UUID | The department's id. |
positions[].department.name | string or null | The department's name. |
positions[].is_current | boolean | Whether the position is marked as current. |
positions[].is_future | boolean | Whether the position is marked as a future position. |
positions[].start_date | date or null | When the position started. |
positions[].end_date | date or null | When the position ended. |
positions[].terms | array | Election terms on a termed position, earliest first. Empty for other positions. |
positions[].terms[].id | UUID | The term's id. The same term has the same id on every person. |
positions[].terms[].name | string or null | The term's name, for example 2024-2026 Term. |
positions[].terms[].scenario | string or null | elected or appointed. null if not set. |
positions[].terms[].region | object or null | The region the term is for. null if none is set. |
positions[].terms[].region.id | UUID | The region's id. |
positions[].terms[].region.name | string or null | The region's name. |
positions[].terms[].start_date | date or null | The term's first day. |
positions[].terms[].end_date | date or null | The term's last day. |
organizations | array | Every organization the person belongs to, in the order they were linked. Deleted organizations are left out. The positions the person holds there are in positions. |
organizations[].organization_id | UUID | The organization. An id from /organizations. |
organizations[].is_contact_person | boolean | Whether the person is that organization's default contact. |
member_types | array | The person's member types. |
member_types[].id | UUID | The member type's id. |
member_types[].name | string or null | The member type's name. |
member_type_history | array | Member types with the dates Engagifii recorded for them, earliest first. See Member type history. |
member_type_history[].member_type_id | UUID | The member type. Matches member_types[].id. |
member_type_history[].name | string or null | The member type's name. |
member_type_history[].start_date | date or null | When the person got the member type. |
member_type_history[].end_date | date or null | When the member type ended. null if Engagifii recorded no end. |
member_type_history[].is_current | boolean | true only when end_date is null and the member type is also in member_types. |
tags | array of strings | The person's tags, in alphabetical order. |
custom_fields | array | The workspace's own fields that have a value for this person. See Custom fields. |
email_opt_outs | array | The person's email addresses that opted out of email, oldest first. Opting back in removes the entry. |
email_opt_outs[].email | string or null | The address that opted out. |
email_opt_outs[].group_id | UUID or null | null when the address opted out of all email from Engagifii. Otherwise the group whose mailing list it left, an id from /groups. |
email_opt_outs[].opted_out_at | date-time or null | When the address opted out. |
last_login_at | date-time or null | When the person last signed in to Engagifii. null if they never have. |
created_at | date-time | When the person was added. |
updated_at | date-time | When the person's own details last changed. |
/people returns at most 200 people a page (page_size 1 to 200), because each person carries many details.
Member type history
Engagifii started recording member type dates when the workspace first changed a member type, so a member type held since before then has no history entry. Engagifii sometimes removes a member type from a person without closing its history entry. An end_date of null alone therefore does not mean the person still holds the type: use is_current, or member_types, for what the person holds today. Member types the workspace has deleted are left out.
Personal details
date_of_birth, gender, race and ethnicity are the standard profile fields. A workspace can also keep similar information in its own custom fields; those are in custom_fields. See the guidance under Custom fields on storing personal data.
Keeping people in sync
updated_at moves when the person's own details change. A change to only their positions, terms, organizations, member types, member type history, tags, custom fields, emails, phones, addresses or email opt-outs may not move it, and a removed member type or an opt-in leaves no trace for updated_since to find. Reload people in full from time to time.
Organizations
An organization is a company, agency, school or other body in the workspace. People link to it through primary_organization_id and positions[].organization_id, and invoices and payments use the same id. Inactive organizations are included with "status": "inactive".
| Endpoint | Meaning |
|---|---|
GET /organizations | List organizations, one page at a time. |
GET /organizations/ids | The id of every organization that has not been deleted. |
GET /organizations/{id} | One organization. 404 if it does not exist or has been deleted. |
Filters
| Parameter | Type | Meaning |
|---|---|---|
status | string | active or inactive. |
q | string | Only organizations whose name contains this text. Up to 200 characters. |
Example
json
{
"id": "9b21…",
"name": "Springfield Water District",
"type": "Special District",
"email": "info@example.org",
"website": "https://www.example.org",
"status": "active",
"time_zone": "Central Standard Time",
"is_parent": false,
"is_child": true,
"emails": [
{ "email": "info@example.org", "type": "General Email", "is_primary": true }
],
"phones": [
{ "phone": "555-0100", "type": "Main Phone", "is_primary": false }
],
"addresses": [
{
"type": "Billing Address",
"line_1": "200 Lake Road",
"line_2": null,
"city": "Springfield",
"state": "IL",
"postal_code": "62702",
"country": "United States",
"is_billing": true
}
],
"tags": ["Utility"],
"related_organizations": [
{ "organization_id": "0d4f…", "relation": "Parent" }
],
"key_contacts": [
{ "person_id": "3f0c…", "type": "Billing" },
{ "person_id": "3f0c…", "type": "Member Organization Lead" }
],
"group_ids": ["4e7a…"],
"custom_fields": [
{ "field_id": "b3c1…", "name": "Population Served", "group": "Profile", "type": "number", "value": 48000 }
],
"created_at": "2014-02-11T16:20:00Z",
"updated_at": "2026-09-14T11:47:03Z"
}Fields
| Field | Type | Meaning |
|---|---|---|
id | UUID | The organization's id. |
name | string or null | The organization's name. |
type | string or null | The organization type set up in the workspace, for example Special District. |
email | string or null | The organization's main email address. |
website | string or null | The organization's website. |
status | string | active or inactive. |
time_zone | string or null | The organization's time zone as stored in Engagifii. |
is_parent | boolean | Whether the organization is marked as a parent organization. |
is_child | boolean | Whether the organization is marked as a child organization. |
emails | array | Every email address on the organization. See Emails, phones and addresses. |
phones | array | Every phone number on the organization. Organizations have no main phone, so is_primary is always false. |
addresses | array | Every address on the organization. |
tags | array of strings | The organization's tags, in alphabetical order. |
related_organizations | array | Other organizations this one is related to. Only organizations that have not been deleted are listed. |
related_organizations[].organization_id | UUID | The related organization. An id from /organizations. |
related_organizations[].relation | string or null | The kind of relation, as named in the workspace. |
key_contacts | array | The organization's key contacts, one entry per person and contact type, by the person's last name. Deleted people are left out. |
key_contacts[].person_id | UUID | The contact. An id from /people. |
key_contacts[].type | string or null | The kind of key contact, as named in the workspace, for example Billing or Member Organization Lead. |
group_ids | array of UUIDs | The groups associated with the organization (its Groups tab in Engagifii), by group name. Ids from /groups. Deleted groups are left out. |
custom_fields | array | The workspace's own fields that have a value for this organization. See Custom fields. |
created_at | date-time | When the organization was added. |
updated_at | date-time | When the organization's own details last changed. |
Keeping organizations in sync
A change to only an organization's custom fields, tags, emails, phones, addresses, related organizations, key contacts or groups may not move updated_at. Reload organizations in full from time to time.
Emails, phones and addresses
People and organizations carry the same emails, phones and addresses arrays. Each entry comes from one of the contact fields the workspace has set up, such as "Work Email" or "Mailing Address". Entries are in the order the workspace arranges its fields. Empty values are left out.
| Field | Type | Meaning |
|---|---|---|
emails[].email | string | The email address. |
emails[].type | string or null | The name of the field it is held in, for example Work Email. |
emails[].is_primary | boolean | true when this address is the same as the record's email, ignoring case. |
phones[].phone | string | The phone number, as entered. |
phones[].type | string or null | The name of the field it is held in, for example Mobile Phone. |
phones[].is_primary | boolean | true when this number is the same as the person's phone. Always false for organizations. |
addresses[].type | string or null | The name of the field it is held in, for example Mailing Address. |
addresses[].line_1 | string or null | First address line. |
addresses[].line_2 | string or null | Second address line. |
addresses[].city | string or null | |
addresses[].state | string or null | |
addresses[].postal_code | string or null | |
addresses[].country | string or null | |
addresses[].is_billing | boolean | Whether this is the field the workspace uses as the billing address. |
Custom fields
custom_fields lists the fields a workspace has added to people or organizations, with this record's value. Fields with no value for the record are left out. Entries are in the order the workspace arranges its fields.
| Field | Type | Meaning |
|---|---|---|
custom_fields[].field_id | UUID | The field's id. The same field has the same id on every record. |
custom_fields[].name | string or null | The field's name. |
custom_fields[].group | string or null | The name of the section the field is in. null if it is in none. |
custom_fields[].type | string | The kind of field. See below. |
custom_fields[].value | string, number, object or array | The value. Its shape depends on type. |
type | value |
|---|---|
date | Date string, YYYY-MM-DD. |
date_range | Object { "from": date or null, "to": date or null }. |
number | Number, for example 12.5. |
dropdown, smart_dropdown | String with the chosen option, or an array of strings when several options can be chosen. |
radio | String with the chosen option. |
html | String of HTML, returned exactly as stored. |
file | { "has_file": true }. The file itself is not returned. |
text, position, department, position_dates, total_time_worked, terms, terms_scenario, region, other | String, or an array of strings when the field holds several choices. |
Guidance for handling custom fields:
- HTML is not sanitised.
htmlvalues are returned as they were entered. If you display them, sanitise them first. - Values can be sensitive. Every custom field the workspace created is returned, including fields that may hold personal data such as a birth date or ethnicity. The same goes for a person's
date_of_birth,gender,raceandethnicity. Store the data securely and limit who can see it.
Groups
A group is a named list of people in the workspace. A static group names its people; a dynamic group selects people by rules. The group record does not include its members; get them from /groups/{id}/members.
| Endpoint | Meaning |
|---|---|
GET /groups | List groups, one page at a time. |
GET /groups/ids | The id of every group that has not been deleted. |
GET /groups/{id} | One group. 404 if it does not exist or has been deleted. |
GET /groups/{id}/members | The ids of the people in the group right now. |
Filters
| Parameter | Type | Meaning |
|---|---|---|
type | string | static, dynamic or membership. |
Example
json
{
"id": "4e7a…",
"name": "2026 Conference Speakers",
"description": "Everyone presenting at the annual conference.",
"type": "static",
"email": "speakers@example.org",
"time_zone": "Eastern Standard Time",
"status": "active",
"owner_person_ids": ["3f0c…"],
"created_at": "2026-01-15T10:00:00Z",
"updated_at": "2026-08-02T17:31:40Z"
}Fields
| Field | Type | Meaning |
|---|---|---|
id | UUID | The group's id. |
name | string or null | The group's name. |
description | string or null | The group's description. |
type | string | static, dynamic, membership, or other for any other kind. |
email | string or null | The group's email address. |
time_zone | string or null | The group's time zone as stored in Engagifii. |
status | string | active or inactive. |
owner_person_ids | array of UUIDs | The people who own the group. Ids from /people. Deleted people are left out. |
created_at | date-time | When the group was created. |
updated_at | date-time | When the group's own details last changed. |
GET /groups/{id}/members
Returns the ids of the people in the group right now, as Engagifii works them out from the group's rules. Deleted people are left out. A group with no rules yet has no members.
json
{ "data": ["0a1b…", "3f0c…"], "next_cursor": null }- Paging works like the
/idsendpoints:page_sizedefaults to and maxes out at 5000, passnext_cursorback ascursoruntil it isnull, and the ids are not in alphabetical order. 404if the group does not exist or has been deleted.- Each id is an
idfrom/people. - A page for a large dynamic group can take several seconds.
Keeping groups in sync
- Members have no change time, and membership changes whenever people change, without touching the group. To sync a group's members, fetch the full list again and replace what you hold.
- A change to only a group's owners may not move
updated_at. Reload groups in full from time to time.
Committees
A committee is a body in the workspace, such as a board or a working group, with a set of positions people can hold. Who holds them is in /committee-members.
| Endpoint | Meaning |
|---|---|
GET /committees | List committees, one page at a time. |
GET /committees/ids | The id of every committee that has not been deleted. |
GET /committees/{id} | One committee. 404 if it does not exist or has been deleted. |
There are no filters beyond paging.
Example
json
{
"id": "d81b…",
"name": "Board of Directors",
"description": "Elected board of the association.",
"type": { "id": "62c0…", "name": "Governance" },
"organization_id": null,
"uses_terms": true,
"status": "active",
"positions": [
{ "id": "f5a2…", "name": "Chair", "seat_limit": 1 },
{ "id": "f5a3…", "name": "Director", "seat_limit": null }
],
"tags": ["Elected"],
"created_at": "2019-04-01T08:00:00Z",
"updated_at": "2026-06-20T13:12:09Z"
}Fields
| Field | Type | Meaning |
|---|---|---|
id | UUID | The committee's id. |
name | string or null | The committee's name. |
description | string or null | The committee's description. |
type | object or null | The committee type. null if none is set. |
type.id | UUID | The committee type's id. |
type.name | string or null | The committee type's name. |
organization_id | UUID or null | The organization the committee belongs to. An id from /organizations. |
uses_terms | boolean | Whether the committee uses terms. |
status | string | active or inactive. |
positions | array | The committee's positions, in the order the workspace sets. Removed positions are left out. |
positions[].id | UUID | The position's id. Matches position.id on /committee-members. |
positions[].name | string or null | The position's name, for example Chair. |
positions[].seat_limit | integer or null | How many people can hold the position at once. null means no limit. |
tags | array of strings | The committee's tags, in alphabetical order. Tags the workspace has deleted are left out. |
created_at | date-time | When the committee was created. |
updated_at | date-time | The later of the committee's own last change and the last change to one of its positions. |
Keeping committees in sync
Removing a committee or one of its positions, renaming a committee type, or changing a committee's tags does not move updated_at, so updated_since misses these changes. A workspace has few committees: reload them in full on every sync and compare with /committees/ids.
Committee members
A committee member record is one seat: a person holding a position on a committee for a period. Past seats are included as well as current ones.
| Endpoint | Meaning |
|---|---|
GET /committee-members | List seats, one page at a time. |
GET /committee-members/ids | The id of every seat that has not been deleted. |
GET /committee-members/{id} | One seat. 404 if it does not exist or has been deleted. |
Filters
| Parameter | Type | Meaning |
|---|---|---|
committee_id | UUID | Only seats on this committee. |
person_id | UUID | Only seats held by this person. |
current | string | true for seats that are current today (see is_current), false for seats that have ended. |
Example
json
{
"id": "8c66…",
"committee_id": "d81b…",
"person_id": "3f0c…",
"position": { "id": "f5a2…", "name": "Chair" },
"start_date": "2025-07-01",
"end_date": "2027-06-30",
"is_current": true,
"status": "active",
"created_at": "2025-06-12T15:40:00Z",
"updated_at": "2025-06-12T15:40:00Z"
}Fields
| Field | Type | Meaning |
|---|---|---|
id | UUID | The seat's id. |
committee_id | UUID | The committee. An id from /committees. |
person_id | UUID | The person holding the seat. An id from /people. |
position | object or null | The position held. null if none is set. |
position.id | UUID | The position's id. Matches positions[].id on /committees, unless the position has since been removed from the committee. |
position.name | string or null | The position's name. |
start_date | date or null | The seat's first day. |
end_date | date or null | The seat's last day. null if it has no end date. |
is_current | boolean | true if the seat has no end date, or its end date has not passed (the seat is current through the whole of end_date, UTC). Only the end date counts, so a seat that starts in the future is also current. |
status | string | active or inactive. |
created_at | date-time | When the seat was added. |
updated_at | date-time | The later of the seat's own last change and the last change to its position, such as a rename. |
Keeping committee members in sync
is_currentis worked out when you make the request. When a seat's end date passes,is_currentchanges butupdated_atdoes not. Recompute it fromend_datein your copy, or reload seats in full from time to time.- Seats of deleted committees and deleted people are left out of every endpoint. When a committee or person is deleted, its seats disappear without a deleted record in
updated_since. Use/committee-members/idsto find them.
Profile change requests
A profile change request is a change to a person or organization record made through Engagifii's profile screens, the add-person flow or the deactivate-person flow. It lists each changed field with its old, requested and approved value, who made the change and, where an approval workflow applied, each approval step.
Most requests are approved the moment they are made, because no approval workflow applied or the editor may skip approval. These are staff edits recorded as approved requests. Engagifii changes the record only when a request is approved; the value it wrote is applied_value.
This is not a complete change history. Registration and sign-up forms, imports, member type and member status changes and some profile header edits update records without a request. Changes to sign-in roles are not returned.
| Endpoint | Meaning |
|---|---|
GET /profile-change-requests | List requests, one page at a time. |
GET /profile-change-requests/ids | The id of every request. |
GET /profile-change-requests/{id} | One request. 404 if it does not exist. |
Filters
| Parameter | Type | Meaning |
|---|---|---|
person_id | UUID | Only requests on this person. |
organization_id | UUID | Only requests on this organization. |
status | string | pending, approved, denied or cancelled. |
change_type | string | edit, addition, deactivation or deletion. |
Example
json
{
"id": "e41c…",
"number": "PCR-20931",
"record": { "type": "person", "id": "3f0c…" },
"change_type": "edit",
"status": "approved",
"requested_by_person_id": "3f0c…",
"decided_by_person_id": "51ad…",
"changes": [
{
"kind": "base",
"name": "Title",
"custom_field_id": null,
"value_type": "text",
"old_value": "Program Manager",
"requested_value": "Director of Programs",
"approved_value": null,
"applied_value": "Director of Programs",
"is_primary": false
},
{
"kind": "custom",
"name": "Member Since",
"custom_field_id": "a90d…",
"value_type": "date",
"old_value": null,
"requested_value": "06/01/2015",
"approved_value": null,
"applied_value": "06/01/2015",
"is_primary": false
}
],
"steps": [
{
"sequence": 1,
"name": "Membership review",
"workflow": "Profile changes",
"approver_person_id": "51ad…",
"status": "approved",
"acted_at": "2026-10-29T15:12:40Z",
"acted_by_person_id": null,
"deny_reason": null,
"comment": "Confirmed with the member.",
"decided_by_timeout": false,
"is_backup_approver": false
}
],
"created_at": "2026-10-28T19:03:11Z",
"decided_at": "2026-10-29T15:12:41Z",
"updated_at": "2026-10-29T15:12:41Z"
}Fields
| Field | Type | Meaning |
|---|---|---|
id | UUID | The request's id. |
number | string or null | The request number Engagifii shows. It is not unique: Engagifii has reused some numbers. Use id as the key. |
record | object | The record the request changes. |
record.type | string | person or organization. |
record.id | UUID or null | An id from /people or /organizations. For an addition, the new person's id is set only once the request is approved, so it can be null before then. |
change_type | string | edit, addition (a new person), deactivation, deletion, or other for any other kind. |
status | string | pending, approved, denied, cancelled, or other for any other status. |
requested_by_person_id | UUID or null | The person who made the change in Engagifii, shown there as the requestor. |
decided_by_person_id | UUID or null | The person who last changed the request after it was made, usually the one who decided it. null if no one has. |
changes | array | The changed fields. |
changes[].kind | string | base for a standard profile field, custom for one of the workspace's custom fields, status for the record's active flag, other otherwise. |
changes[].name | string or null | The field's name. For status, always active. For custom, the field's current name. |
changes[].custom_field_id | UUID or null | For custom, the field's id, as custom_fields[].field_id on people and organizations. null otherwise. |
changes[].value_type | string | What kind of value the field holds: text, html, date, dropdown, radio, location, email, phone, organizations or active_flag. See Change request values. |
changes[].old_value | string or null | The value before the change. |
changes[].requested_value | string or null | The value asked for. |
changes[].approved_value | string or null | The value an approver entered in place of the requested one. null if the approver did not change it. |
changes[].applied_value | string or null | The value Engagifii wrote to the record: approved_value if there is one, otherwise requested_value. "" when the approver cleared a dropdown. null unless status is approved. |
changes[].is_primary | boolean | For email and phone fields, whether the value is marked as primary. |
steps | array | The approval steps, in sequence order. Empty when no approval workflow applied. |
steps[].sequence | integer | The step's position in the workflow. |
steps[].name | string or null | The step's name. |
steps[].workflow | string or null | The name of the approval workflow. |
steps[].approver_person_id | UUID or null | The person the step was assigned to. |
steps[].status | string | pending, approved, denied, not_applicable, or other. |
steps[].acted_at | date-time or null | When the step was approved or denied. |
steps[].acted_by_person_id | UUID or null | When an administrator acted in place of the assigned approver, that administrator. null otherwise. |
steps[].deny_reason | string or null | The reason picked when the step was denied. |
steps[].comment | string or null | The approver's comment, exactly as typed. |
steps[].decided_by_timeout | boolean | true when Engagifii decided the step by its timeout rule. |
steps[].is_backup_approver | boolean | true when the approver is a backup added after the step timed out. |
created_at | date-time | When the request was made. See the note on older organization requests below. |
decided_at | date-time or null | When the request was last changed after it was made, usually its decision. null while nothing has changed it. |
updated_at | date-time | decided_at if set, otherwise created_at. |
Change request values
Values are returned as strings, exactly as Engagifii stores them in the request. They are not converted to the formats used on /people and /organizations:
value_type | Stored as |
|---|---|
date | Text in MM/dd/yyyy form, for example 06/01/2015. |
phone | The phone number as formatted text. |
dropdown, radio | JSON text such as {"id": "…", "value": "Gold"}. |
location | JSON text of an address. |
html | HTML, as stored. |
text, email, organizations, active_flag | Text as stored. The tags field is a comma-separated list, and its requested_value can hold only the tags added. |
- Text is not sanitised. Values,
steps[].commentandsteps[].deny_reasonare returned as entered, andhtmlvalues are HTML. Never render them unescaped. - Values can be sensitive. A request can change any field, including personal data. Store the data securely.
Keeping profile change requests in sync
- Requests are never deleted, so the deleted short form never appears.
/profile-change-requests/idslists every request. updated_atmoves when a request is made and when it is decided. An approval step acted on before the final decision may not move it, so reload pending requests (status=pending) from time to time.created_aton organization requests made before about 20 February 2025 is US Eastern time written as UTC, so those times are 4 or 5 hours early.
Files
A file is a document staff uploaded on the Documents tab of a person, organization, course, class or event, or a web link or hosted video added there instead. The API returns each file's name, type, size and the record it belongs to, never the file's content.
| Endpoint | Meaning |
|---|---|
GET /files | List files, one page at a time. |
GET /files/ids | The id of every file that has not been deleted or moved to Trash. |
GET /files/{id} | One file. 404 if it does not exist, has been deleted or is in Trash. |
Filters
| Parameter | Type | Meaning |
|---|---|---|
record_id | UUID | Only files on this record, including its sub-folders. For example a person's id from /people or a class's id from /classes. |
Example
json
{
"id": "c2d9…",
"file_name": "Signed membership agreement.pdf",
"file_type": "pdf",
"mime_type": "application/pdf",
"size_bytes": 248113,
"link_url": null,
"video_host": null,
"record": { "type": "organization", "id": "9b21…" },
"created_at": "2026-02-03T14:21:07Z",
"updated_at": "2026-02-03T14:21:07Z"
}Fields
| Field | Type | Meaning |
|---|---|---|
id | UUID | The file's id. |
file_name | string or null | The name Engagifii shows for the file. |
file_type | string or null | The kind of file: pdf, doc, docx, png, jpg, jpeg, tiff, txt, wps, wpd, xls, xlsx, odf, mp4, zip or link. null for any other kind. |
mime_type | string or null | The file's media type, for example application/pdf. |
size_bytes | integer or null | The file's size in bytes. null for web links and hosted videos. |
link_url | string or null | For a web link added instead of an upload, its address. null otherwise. |
video_host | string or null | For a video kept on another site instead of an upload: youtube, vimeo or other. The video's address is not returned, as it can be a private link. null otherwise. |
record | object | The record the file belongs to. |
record.type | string | person, organization, course, class, event, venue, room, group, endorsement, or other when Engagifii cannot tell. |
record.id | UUID or null | The record's id, for example an id from /people or /organizations. null when Engagifii cannot tell. |
created_at | date-time | When the file was added. |
updated_at | date-time | When the file last changed, including when it was moved to Trash. |
Keeping files in sync
Moving a file to Trash in Engagifii deletes its content at once, so the API treats a file in Trash as deleted: it comes back in the deleted short form with updated_since, and leaves /files/ids.
