Update CRM Object Attribute
Update a single attribute definition on a Zeeg CRM object with a partial PATCH that changes only the fields you send, like label, options, or currency
curl --request PATCH \
--url https://api.zeeg.me/v2/crm/objects/{slug}/attributes/{attributeKey} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{}'import requests
url = "https://api.zeeg.me/v2/crm/objects/{slug}/attributes/{attributeKey}"
payload = {}
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({})
};
fetch('https://api.zeeg.me/v2/crm/objects/{slug}/attributes/{attributeKey}', 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.zeeg.me/v2/crm/objects/{slug}/attributes/{attributeKey}",
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([
]),
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.zeeg.me/v2/crm/objects/{slug}/attributes/{attributeKey}"
payload := strings.NewReader("{}")
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.zeeg.me/v2/crm/objects/{slug}/attributes/{attributeKey}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.zeeg.me/v2/crm/objects/{slug}/attributes/{attributeKey}")
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 = "{}"
response = http.request(request)
puts response.read_body{
"success": true,
"status": 200,
"attribute": {
"key": "customer_status",
"label": "Status",
"type": "select",
"isRequired": true,
"isStandard": false,
"isUnique": false,
"isArchived": false,
"options": [
{
"id": 1,
"value": "Lead",
"color": "warning"
},
{
"id": 2,
"value": "Active",
"color": "success"
},
{
"id": 3,
"value": "Churned",
"color": "red"
}
],
"createdAt": "2025-06-15T10:00:00+00:00",
"updatedAt": "2025-06-20T14:00:00+00:00"
}
}{
"success": false,
"message": "Attribute type cannot be changed.",
"status": 400
}{
"message": "Unauthenticated."
}{
"error": {
"type": "insufficient_scope",
"message": "Your token is missing the required scope: crm:write.",
"error_id": "a15b5b16-02c6-423b-be78-48627f4b80fe",
"required_scopes": [
"crm:write"
]
}
}{
"success": true,
"message": "<string>",
"status": 123
}{
"message": "The given data was invalid.",
"errors": {
"field_name": [
"The field_name field is required."
]
}
}Updatable fields
| Field | Applies to | Notes |
|---|---|---|
label | All types | |
isRequired | All types | |
isArchived | All types | Archived attributes are hidden in the UI but data is retained |
options | select, multiselect, status | Full replacement — see below |
relatedObjectLabel | relation | Display label shown in the UI for the linked object |
currencyDisplay | currency | code, name, or symbol |
currencyDecimal | currency | Show decimal places |
currencyGrouping | currency | Use thousands separator |
Immutable fields
| Field | Reason |
|---|---|
type | Changing type would corrupt existing record data |
key | Used as the stable identifier in all record values |
relatedObjectSlug | Changing the target would orphan existing linked records |
currency | Changing the currency code would make stored amounts misleading |
Updating options (select / multiselect / status)
When you send options, the list fully replaces the current options:
- Include
idon existing options you want to keep — existing record values are preserved. - Omit
idfor new options — the server assigns a new ID. - Exclude an option entirely to delete it — existing records that held that value will have the value cleared.
{
"options": [
{ "id": 12, "value": "Active", "color": "success" },
{ "id": 13, "value": "On Hold", "color": "warning" },
{ "value": "Churned", "color": "gray" }
]
}
Standard attributes
Standard attributes (e.g.first_name, emails on people) cannot be updated and return 400.Authorizations
Path Parameters
The object slug.
"people"
The attribute key (slug) to update. Retrieve available keys from GET /crm/objects/{slug}.
"customer_status"
Body
New display label.
255"Status"
Whether a value is required when creating a record.
true
Set to true to hide this attribute from the UI without deleting data.
false
Replacement options list for select, multiselect, and status types. Include existing option id values to preserve them.
Hide child attributes
Hide child attributes
The option label shown in the UI and stored as the attribute value.
512"Active"
Color name for the option. Allowed values: gray, primary, warning, success, cyan, sky, violet, fuchsia, rose, blue, green, red, pink, black, yellow, orange.
"success"
Server-assigned option ID. Omit when adding a new option; include when updating an existing one to preserve it.
1
relation only — updated display label for the linked object. The target object (relatedObjectSlug) cannot change.
255"Contact Person"
currency only — how the currency value is shown: code, name, or symbol.
code, name, symbol "code"
currency only — show decimal places.
false
currency only — use a thousands separator.
false
Response
OK
true
200
Definition of a single attribute on a CRM object.
Hide child attributes
Hide child attributes
Attribute key used when reading or writing record values.
"job_title"
Human-readable label shown in the UI.
"Job Title"
Attribute data type. Cannot be changed after creation.
text, number, phone_number, date, datetime, checkbox, select, multiselect, rating, relation, status, user, currency "text"
Whether a value is required when creating a record.
false
true for built-in attributes, false for custom attributes added by your workspace.
false
Whether values must be unique across all records. Applies to text, phone, and number types.
false
Whether the attribute is archived. Archived attributes are hidden from the UI but their data is preserved.
false
ISO 8601 timestamp when the attribute was created.
"2025-06-01T10:00:00+00:00"
ISO 8601 timestamp when the attribute was last updated.
"2025-06-01T10:00:00+00:00"
Available options. Present only for select, multiselect, and status attributes.
Hide child attributes
Hide child attributes
The option label shown in the UI and stored as the attribute value.
512"Active"
Color name for the option. Allowed values: gray, primary, warning, success, cyan, sky, violet, fuchsia, rose, blue, green, red, pink, black, yellow, orange.
"success"
Server-assigned option ID. Omit when adding a new option; include when updating an existing one to preserve it.
1
Slug of the related object. Present only for relation attributes. Immutable after creation.
"companies"
Display label for the relation. Present only for relation attributes. Can be updated via PATCH.
"Company"
Cardinality of the relation. Present only for relation attributes.
one_to_one, many_to_one, one_to_many, many_to_many "many_to_one"
true when relationType is one_to_many or many_to_many. Present only for relation attributes.
false
ISO 4217 currency code. Present only for currency attributes. Immutable after creation.
"EUR"
How the currency value is displayed. Present only for currency attributes.
code, name, symbol "symbol"
Whether decimal places are shown. Present only for currency attributes.
true
Whether a thousands separator is used. Present only for currency attributes.
true
curl --request PATCH \
--url https://api.zeeg.me/v2/crm/objects/{slug}/attributes/{attributeKey} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{}'import requests
url = "https://api.zeeg.me/v2/crm/objects/{slug}/attributes/{attributeKey}"
payload = {}
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({})
};
fetch('https://api.zeeg.me/v2/crm/objects/{slug}/attributes/{attributeKey}', 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.zeeg.me/v2/crm/objects/{slug}/attributes/{attributeKey}",
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([
]),
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.zeeg.me/v2/crm/objects/{slug}/attributes/{attributeKey}"
payload := strings.NewReader("{}")
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.zeeg.me/v2/crm/objects/{slug}/attributes/{attributeKey}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.zeeg.me/v2/crm/objects/{slug}/attributes/{attributeKey}")
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 = "{}"
response = http.request(request)
puts response.read_body{
"success": true,
"status": 200,
"attribute": {
"key": "customer_status",
"label": "Status",
"type": "select",
"isRequired": true,
"isStandard": false,
"isUnique": false,
"isArchived": false,
"options": [
{
"id": 1,
"value": "Lead",
"color": "warning"
},
{
"id": 2,
"value": "Active",
"color": "success"
},
{
"id": 3,
"value": "Churned",
"color": "red"
}
],
"createdAt": "2025-06-15T10:00:00+00:00",
"updatedAt": "2025-06-20T14:00:00+00:00"
}
}{
"success": false,
"message": "Attribute type cannot be changed.",
"status": 400
}{
"message": "Unauthenticated."
}{
"error": {
"type": "insufficient_scope",
"message": "Your token is missing the required scope: crm:write.",
"error_id": "a15b5b16-02c6-423b-be78-48627f4b80fe",
"required_scopes": [
"crm:write"
]
}
}{
"success": true,
"message": "<string>",
"status": 123
}{
"message": "The given data was invalid.",
"errors": {
"field_name": [
"The field_name field is required."
]
}
}