contactId and propertyId are supplied directly in the URL path (see the request above). propertyId identifies which custom field you're setting (e.g. "Loyalty Tier") — it is not a value-record ID.ℹ️ To find the propertyIdfor a custom field, call List Contact Properties — each entry returned there includes theidyou need here.
value: null removes the property from the contact entirely — this endpoint doubles as an implicit clear/unset.GET /v1/contacts/{contactId}/history. No-op changes (re-setting the same value) are not logged.value is null → error: Property '{Name}' is required.Select, value must match one of the property's predefined selectOptions → otherwise: Invalid select option '...' for property '...'.Text, Number, and Date types have no extra validation beyond the required check.| Type | Code | Value shape |
|---|---|---|
| Text | 1 | string |
| Number | 2 | decimal |
| Select | 3 | must match one of the property's selectOptions |
| Date | 4 | DateTime |
curl --location --globoff --request PUT 'https://api.voxa.sa/v1/contacts/{{contactId}}/properties/{{property_id}}' \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{}'{
"workspaceId": "d307b8...............",
"name": "أحمد نصحي | هاتف",
"phoneNumber": "+9665...........",
"contactType": 1,
"email": "noshy@hatif.io",
"company": null,
"position": null,
"customFields": null,
"notes": [],
"customProperties": [
{
"propertyDefinitionId": "3a1d7c...............",
"propertyName": "Loyalty Tier",
"propertyType": 3,
"textValue": null,
"numberValue": null,
"dateValue": null,
"selectValue": "VIP"
}
],
"lastModificationTime": "2026-06-16T12:03:31.995983",
"lastModifierId": null,
"creationTime": "2025-04-23T19:24:17.465921",
"creatorId": "3a1cd6...............",
"id": "3a18a7..............."
}