Create a household
Creates an active household and attaches the primary plus deduplicated additional donors under one membership lock. Every member must be active in this organization and outside any existing household. 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 POST \
--url https://api.gratona.com/v1/admin/households \
--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."
}
]
}
'import requests
url = "https://api.gratona.com/v1/admin/households"
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."
}
]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
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.'
}
]
})
};
fetch('https://api.gratona.com/v1/admin/households', 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",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
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.'
]
]
]),
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"
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}")
req, _ := http.NewRequest("POST", 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.post("https://api.gratona.com/v1/admin/households")
.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}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gratona.com/v1/admin/households")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.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}"
response = http.request(request)
puts response.read_body{
"success": true,
"message": "Household created 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.
Body
Nonblank household name.
255"Doe household"
Active organization donor, automatically included in membership.
42
Show child attributes
Show child attributes
Household custom values; request accepts a JSON object or list.
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
curl --request POST \
--url https://api.gratona.com/v1/admin/households \
--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."
}
]
}
'import requests
url = "https://api.gratona.com/v1/admin/households"
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."
}
]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
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.'
}
]
})
};
fetch('https://api.gratona.com/v1/admin/households', 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",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
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.'
]
]
]),
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"
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}")
req, _ := http.NewRequest("POST", 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.post("https://api.gratona.com/v1/admin/households")
.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}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gratona.com/v1/admin/households")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.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}"
response = http.request(request)
puts response.read_body{
"success": true,
"message": "Household created 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."
}