Skip to content
POST /member/attributes/upsert

Sets field values for up to 200 members in one call — the Elaichi app sends a CSV in batches of 200. Name each member by `email` or `user_id` (exactly one). Each row has its own outcome: good rows are written even when others fail, and `errors` lists every failed row by its index in `rows`, in order. Row codes: `member_not_found`, `self_target` (your own row — nobody sets their own), `member_not_manageable` (they hold a permission you lack), `duplicate_row` (a later row for the same member), `attribute_unknown`, `attribute_invalid`, `attribute_scim_managed`, `attribute_too_large`. An empty `attributes` is "no change". Only a malformed body fails the whole call (400 `validation_error`). Requires `member:manage`. A browser session must also pass a fresh step-up reauthentication in the app (without it the call answers `428 step_up_required`). An organization API token is not challenged.

Request Body

rowsobject[]
attributesRecord<string, any>

Field key → value; null clears it. Each key must be defined (GET /member-attribute, else 400 attribute_unknown) and not filled by SCIM (409 attribute_scim_managed). Text is trimmed, 1-256 characters and may not contain {{; a list holds 1-50 such items; "3" / "true" are accepted for number and boolean fields. A bad value is 400 attribute_invalid (details.key); one member's values together are at most 16 KB (400 attribute_too_large).

emailstring

Matched case-insensitively against org members.

user_idstring

User id (usr_…), instead of email.

Response Body

errorsobject[]
codestring
indexinteger

Position in rows.

keystring

The field the row failed on, when it was one field.

messagestring
failedinteger
unchangedinteger
updatedinteger
curl -X POST 'https://api.elaichi.ai/member/attributes/upsert' \
  -H 'Authorization: Bearer $ELAICHI_API_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"rows":[]}'
const body = {
  "rows": []
};

const response = await fetch('https://api.elaichi.ai/member/attributes/upsert', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer ' + process.env.ELAICHI_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(body),
});

const data = await response.json();
console.log(data);
import os
import requests

url = "https://api.elaichi.ai/member/attributes/upsert"
headers = {
    "Authorization": f"Bearer {os.environ['ELAICHI_API_TOKEN']}",
    "Content-Type": "application/json",
}
payload = {
    "rows": []
}

response = requests.post(url, headers=headers, json=payload)
print(response.json())