Update household and membership
Applies supplied household properties. donor_ids replaces membership while omitted membership stays intact; primary changes can attach the new primary. Referenced donors are checked in the organization before mutation, and existing membership in another household is rejected. Material stewardship impact returns 409 with an expiring confirmation token and required contact/archive repairs; resubmit the same reviewed change with plan_impact_version and plan_repairs.
curl --request PATCH \
--url https://api.gratona.com/v1/admin/households/{household_id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Doe household",
"primary_contact_id": 42,
"address": {
"line1": "10 Main Street",
"line2": "Apt 2",
"city": "Kampala",
"state": "Central",
"postal_code": "00000",
"country": "Uganda"
},
"json_fields": {},
"donor_ids": [
42
],
"plan_impact_version": "issued-household-impact-version",
"plan_repairs": [
{
"plan_id": 42,
"action": "replace_action_donor",
"action_donor_id": 42,
"reason": "Household is being removed."
}
],
"is_active": false
}
'import requests
url = "https://api.gratona.com/v1/admin/households/{household_id}"
payload = {
"name": "Doe household",
"primary_contact_id": 42,
"address": {
"line1": "10 Main Street",
"line2": "Apt 2",
"city": "Kampala",
"state": "Central",
"postal_code": "00000",
"country": "Uganda"
},
"json_fields": {},
"donor_ids": [42],
"plan_impact_version": "issued-household-impact-version",
"plan_repairs": [
{
"plan_id": 42,
"action": "replace_action_donor",
"action_donor_id": 42,
"reason": "Household is being removed."
}
],
"is_active": False
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'Doe household',
primary_contact_id: 42,
address: {
line1: '10 Main Street',
line2: 'Apt 2',
city: 'Kampala',
state: 'Central',
postal_code: '00000',
country: 'Uganda'
},
json_fields: {},
donor_ids: [42],
plan_impact_version: 'issued-household-impact-version',
plan_repairs: [
{
plan_id: 42,
action: 'replace_action_donor',
action_donor_id: 42,
reason: 'Household is being removed.'
}
],
is_active: false
})
};
fetch('https://api.gratona.com/v1/admin/households/{household_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.gratona.com/v1/admin/households/{household_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Doe household',
'primary_contact_id' => 42,
'address' => [
'line1' => '10 Main Street',
'line2' => 'Apt 2',
'city' => 'Kampala',
'state' => 'Central',
'postal_code' => '00000',
'country' => 'Uganda'
],
'json_fields' => [
],
'donor_ids' => [
42
],
'plan_impact_version' => 'issued-household-impact-version',
'plan_repairs' => [
[
'plan_id' => 42,
'action' => 'replace_action_donor',
'action_donor_id' => 42,
'reason' => 'Household is being removed.'
]
],
'is_active' => false
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.gratona.com/v1/admin/households/{household_id}"
payload := strings.NewReader("{\n \"name\": \"Doe household\",\n \"primary_contact_id\": 42,\n \"address\": {\n \"line1\": \"10 Main Street\",\n \"line2\": \"Apt 2\",\n \"city\": \"Kampala\",\n \"state\": \"Central\",\n \"postal_code\": \"00000\",\n \"country\": \"Uganda\"\n },\n \"json_fields\": {},\n \"donor_ids\": [\n 42\n ],\n \"plan_impact_version\": \"issued-household-impact-version\",\n \"plan_repairs\": [\n {\n \"plan_id\": 42,\n \"action\": \"replace_action_donor\",\n \"action_donor_id\": 42,\n \"reason\": \"Household is being removed.\"\n }\n ],\n \"is_active\": false\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://api.gratona.com/v1/admin/households/{household_id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Doe household\",\n \"primary_contact_id\": 42,\n \"address\": {\n \"line1\": \"10 Main Street\",\n \"line2\": \"Apt 2\",\n \"city\": \"Kampala\",\n \"state\": \"Central\",\n \"postal_code\": \"00000\",\n \"country\": \"Uganda\"\n },\n \"json_fields\": {},\n \"donor_ids\": [\n 42\n ],\n \"plan_impact_version\": \"issued-household-impact-version\",\n \"plan_repairs\": [\n {\n \"plan_id\": 42,\n \"action\": \"replace_action_donor\",\n \"action_donor_id\": 42,\n \"reason\": \"Household is being removed.\"\n }\n ],\n \"is_active\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gratona.com/v1/admin/households/{household_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"Doe household\",\n \"primary_contact_id\": 42,\n \"address\": {\n \"line1\": \"10 Main Street\",\n \"line2\": \"Apt 2\",\n \"city\": \"Kampala\",\n \"state\": \"Central\",\n \"postal_code\": \"00000\",\n \"country\": \"Uganda\"\n },\n \"json_fields\": {},\n \"donor_ids\": [\n 42\n ],\n \"plan_impact_version\": \"issued-household-impact-version\",\n \"plan_repairs\": [\n {\n \"plan_id\": 42,\n \"action\": \"replace_action_donor\",\n \"action_donor_id\": 42,\n \"reason\": \"Household is being removed.\"\n }\n ],\n \"is_active\": false\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"message": "Household updated successfully",
"household": {
"id": 42,
"client_id": 42,
"migration_id": "Example",
"name": "Doe household",
"primary_contact_id": 42,
"assigned_fundraiser_user_id": 42,
"donor_ids": [
42
],
"fundraising_profile_json": {},
"json_fields": {},
"is_active": false,
"address_line1": "10 Main Street",
"address_line2": "Apt 2",
"city": "Kampala",
"state": "Central",
"postal_code": "00000",
"country": "Uganda",
"created_at": "2026-10-20T12:00:00Z",
"updated_at": "2026-10-20T12:00:00Z"
}
}{
"message": "Something went wrong. Please try again.",
"status": "error",
"error": "invalid_request",
"code": "DONOR_NOT_FOUND"
}{
"message": "Something went wrong. Please try again.",
"status": "error",
"error": "invalid_request",
"code": "DONOR_NOT_FOUND"
}{
"message": "Not Found",
"status": "error"
}{
"status": "error",
"code": "PLAN_IMPACT_CONFIRMATION_REQUIRED",
"message": "Review household plan impact before saving.",
"data": {
"material_impact": false,
"affected_plans": [
{
"id": 42,
"subject": {
"type": "donor",
"id": 42
},
"stage": "qualifying",
"status": "draft",
"period": {
"start": "2026-10-20",
"end": "2026-10-20"
},
"version": 2,
"action_donor_id": 42,
"scope_version": 2
}
],
"group_plans": [
"<string>"
],
"transfer_candidates": [
"<string>"
],
"scope_changes": [
{
"plan_id": 42,
"next_members": [
{
"member_type": "donor",
"member_id": 42,
"scope_role": "core"
}
],
"eligible_action_donor_ids": [
42
],
"invalid_open_move_ids": [
42
]
}
],
"eligible_action_donor_ids": [
42
],
"collisions": [
{
"plan_id": 42,
"conflicting_plan": {}
}
],
"authority_changes": [
"<string>"
],
"required_repairs": [
{
"plan_id": 42,
"choices": [
"replace_action_donor"
],
"eligible_action_donor_ids": [
42
],
"recommended_action_donor_id": 42
}
],
"proposed_member_donor_ids": [
42
],
"primary_contact_id": 42,
"plan_repairs": [
{
"plan_id": 42
}
],
"command": "household_membership",
"expires_at": "2026-10-20T12:00:00Z",
"impact_version": "issued-household-impact-version",
"conflicts": [
{
"plan_id": 42,
"conflicting_plan": {}
}
]
}
}{
"errors": {},
"status": "error",
"message": "The given data was invalid."
}{
"success": false,
"message": "Failed to update household",
"error": "Unable to complete household change."
}Authorizations
Passport bearer token authentication for legacy admin sessions.
Path Parameters
Record ID in the authenticated organization.
42
Body
Supplied name must be nonblank; omitted name is preserved.
255"Doe household"
Active organization donor, automatically included in membership.
42
Partial address; omitted and null components preserve the existing value.
Show child attributes
Show child attributes
Household custom values; request accepts a JSON object or list.
When supplied, replaces membership after adding the effective primary donor; omission preserves current membership.
Active member donor; primary is included automatically.
Token from a 409 stewardship impact response; required when open plan impact is material.
4096"issued-household-impact-version"
Show child attributes
Show child attributes
Optional stored active flag accepted by the controller.
false
curl --request PATCH \
--url https://api.gratona.com/v1/admin/households/{household_id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Doe household",
"primary_contact_id": 42,
"address": {
"line1": "10 Main Street",
"line2": "Apt 2",
"city": "Kampala",
"state": "Central",
"postal_code": "00000",
"country": "Uganda"
},
"json_fields": {},
"donor_ids": [
42
],
"plan_impact_version": "issued-household-impact-version",
"plan_repairs": [
{
"plan_id": 42,
"action": "replace_action_donor",
"action_donor_id": 42,
"reason": "Household is being removed."
}
],
"is_active": false
}
'import requests
url = "https://api.gratona.com/v1/admin/households/{household_id}"
payload = {
"name": "Doe household",
"primary_contact_id": 42,
"address": {
"line1": "10 Main Street",
"line2": "Apt 2",
"city": "Kampala",
"state": "Central",
"postal_code": "00000",
"country": "Uganda"
},
"json_fields": {},
"donor_ids": [42],
"plan_impact_version": "issued-household-impact-version",
"plan_repairs": [
{
"plan_id": 42,
"action": "replace_action_donor",
"action_donor_id": 42,
"reason": "Household is being removed."
}
],
"is_active": False
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'Doe household',
primary_contact_id: 42,
address: {
line1: '10 Main Street',
line2: 'Apt 2',
city: 'Kampala',
state: 'Central',
postal_code: '00000',
country: 'Uganda'
},
json_fields: {},
donor_ids: [42],
plan_impact_version: 'issued-household-impact-version',
plan_repairs: [
{
plan_id: 42,
action: 'replace_action_donor',
action_donor_id: 42,
reason: 'Household is being removed.'
}
],
is_active: false
})
};
fetch('https://api.gratona.com/v1/admin/households/{household_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.gratona.com/v1/admin/households/{household_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Doe household',
'primary_contact_id' => 42,
'address' => [
'line1' => '10 Main Street',
'line2' => 'Apt 2',
'city' => 'Kampala',
'state' => 'Central',
'postal_code' => '00000',
'country' => 'Uganda'
],
'json_fields' => [
],
'donor_ids' => [
42
],
'plan_impact_version' => 'issued-household-impact-version',
'plan_repairs' => [
[
'plan_id' => 42,
'action' => 'replace_action_donor',
'action_donor_id' => 42,
'reason' => 'Household is being removed.'
]
],
'is_active' => false
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.gratona.com/v1/admin/households/{household_id}"
payload := strings.NewReader("{\n \"name\": \"Doe household\",\n \"primary_contact_id\": 42,\n \"address\": {\n \"line1\": \"10 Main Street\",\n \"line2\": \"Apt 2\",\n \"city\": \"Kampala\",\n \"state\": \"Central\",\n \"postal_code\": \"00000\",\n \"country\": \"Uganda\"\n },\n \"json_fields\": {},\n \"donor_ids\": [\n 42\n ],\n \"plan_impact_version\": \"issued-household-impact-version\",\n \"plan_repairs\": [\n {\n \"plan_id\": 42,\n \"action\": \"replace_action_donor\",\n \"action_donor_id\": 42,\n \"reason\": \"Household is being removed.\"\n }\n ],\n \"is_active\": false\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://api.gratona.com/v1/admin/households/{household_id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Doe household\",\n \"primary_contact_id\": 42,\n \"address\": {\n \"line1\": \"10 Main Street\",\n \"line2\": \"Apt 2\",\n \"city\": \"Kampala\",\n \"state\": \"Central\",\n \"postal_code\": \"00000\",\n \"country\": \"Uganda\"\n },\n \"json_fields\": {},\n \"donor_ids\": [\n 42\n ],\n \"plan_impact_version\": \"issued-household-impact-version\",\n \"plan_repairs\": [\n {\n \"plan_id\": 42,\n \"action\": \"replace_action_donor\",\n \"action_donor_id\": 42,\n \"reason\": \"Household is being removed.\"\n }\n ],\n \"is_active\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gratona.com/v1/admin/households/{household_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"Doe household\",\n \"primary_contact_id\": 42,\n \"address\": {\n \"line1\": \"10 Main Street\",\n \"line2\": \"Apt 2\",\n \"city\": \"Kampala\",\n \"state\": \"Central\",\n \"postal_code\": \"00000\",\n \"country\": \"Uganda\"\n },\n \"json_fields\": {},\n \"donor_ids\": [\n 42\n ],\n \"plan_impact_version\": \"issued-household-impact-version\",\n \"plan_repairs\": [\n {\n \"plan_id\": 42,\n \"action\": \"replace_action_donor\",\n \"action_donor_id\": 42,\n \"reason\": \"Household is being removed.\"\n }\n ],\n \"is_active\": false\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"message": "Household updated successfully",
"household": {
"id": 42,
"client_id": 42,
"migration_id": "Example",
"name": "Doe household",
"primary_contact_id": 42,
"assigned_fundraiser_user_id": 42,
"donor_ids": [
42
],
"fundraising_profile_json": {},
"json_fields": {},
"is_active": false,
"address_line1": "10 Main Street",
"address_line2": "Apt 2",
"city": "Kampala",
"state": "Central",
"postal_code": "00000",
"country": "Uganda",
"created_at": "2026-10-20T12:00:00Z",
"updated_at": "2026-10-20T12:00:00Z"
}
}{
"message": "Something went wrong. Please try again.",
"status": "error",
"error": "invalid_request",
"code": "DONOR_NOT_FOUND"
}{
"message": "Something went wrong. Please try again.",
"status": "error",
"error": "invalid_request",
"code": "DONOR_NOT_FOUND"
}{
"message": "Not Found",
"status": "error"
}{
"status": "error",
"code": "PLAN_IMPACT_CONFIRMATION_REQUIRED",
"message": "Review household plan impact before saving.",
"data": {
"material_impact": false,
"affected_plans": [
{
"id": 42,
"subject": {
"type": "donor",
"id": 42
},
"stage": "qualifying",
"status": "draft",
"period": {
"start": "2026-10-20",
"end": "2026-10-20"
},
"version": 2,
"action_donor_id": 42,
"scope_version": 2
}
],
"group_plans": [
"<string>"
],
"transfer_candidates": [
"<string>"
],
"scope_changes": [
{
"plan_id": 42,
"next_members": [
{
"member_type": "donor",
"member_id": 42,
"scope_role": "core"
}
],
"eligible_action_donor_ids": [
42
],
"invalid_open_move_ids": [
42
]
}
],
"eligible_action_donor_ids": [
42
],
"collisions": [
{
"plan_id": 42,
"conflicting_plan": {}
}
],
"authority_changes": [
"<string>"
],
"required_repairs": [
{
"plan_id": 42,
"choices": [
"replace_action_donor"
],
"eligible_action_donor_ids": [
42
],
"recommended_action_donor_id": 42
}
],
"proposed_member_donor_ids": [
42
],
"primary_contact_id": 42,
"plan_repairs": [
{
"plan_id": 42
}
],
"command": "household_membership",
"expires_at": "2026-10-20T12:00:00Z",
"impact_version": "issued-household-impact-version",
"conflicts": [
{
"plan_id": 42,
"conflicting_plan": {}
}
]
}
}{
"errors": {},
"status": "error",
"message": "The given data was invalid."
}{
"success": false,
"message": "Failed to update household",
"error": "Unable to complete household change."
}