This walks through the hero curl from the marketing site — create a person, declare a new schema attribute, then write the attribute on that person, and watch enum validation reject a bad value.
1. Get an API key
Sign up at $SALTY_WEB/signup — see Introduction → Hosts at a glance for the env vars. After email verification you land on /api with your first sk_live_… key shown ONCE — store it as $SALTY_API_KEY:
export SALTY_API_KEY=sk_live_...
(For purely scripted setups, hit POST $SALTY_API/workspaces/bootstrap with a Supabase JWT to provision a workspace + first key idempotently.)
Only the first 16 characters (sk_live_xxxxxxxx) are stored on the server, hashed with argon2. If you lose the full key, revoke it and create a new one.
2. Create a person
curl $SALTY_API/people \
-H "Authorization: Bearer $SALTY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "jane@acme.com",
"first_name": "Jane",
"last_name": "Doe"
}'
Response:
{
"id": "f30057e8-8f1e-49c3-a06f-481d6f03256a",
"email": "jane@acme.com",
"first_name": "Jane",
"last_name": "Doe",
"primary_company_id": null,
"custom_attributes": {},
"created_at": "2026-05-24T02:45:46.417Z",
"updated_at": "2026-05-24T02:45:46.417Z"
}
3. Add a custom attribute to the People schema
Define a lifecycle_stage enum on the person object. Now every person write that includes custom_attributes.lifecycle_stage is validated against this enum.
curl $SALTY_API/schema/person/attributes \
-H "Authorization: Bearer $SALTY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"attribute_key": "lifecycle_stage",
"display_name": "Lifecycle Stage",
"data_type": "enum",
"enum_values": ["lead", "customer", "churned"]
}'
4. Use the new attribute
curl -X PATCH $SALTY_API/people/<id> \
-H "Authorization: Bearer $SALTY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"custom_attributes":{"lifecycle_stage":"customer"}}'
Returns 200 with the updated person.
5. Watch validation reject a bad value
curl -X PATCH $SALTY_API/people/<id> \
-H "Authorization: Bearer $SALTY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"custom_attributes":{"lifecycle_stage":"vip"}}'
Returns 400 with the precise error envelope:
{
"error": {
"type": "invalid_request",
"code": "attribute_enum_invalid",
"message": "\"vip\" is not a valid value for \"lifecycle_stage\"; expected one of: lead, customer, churned",
"param": "lifecycle_stage"
}
}
Where to go next