> ## Documentation Index
> Fetch the complete documentation index at: https://docs.soneka.africa/llms.txt
> Use this file to discover all available pages before exploring further.

# Attributes: Structured Customer Data for WhatsApp at Scale

> Capture, store, and use structured customer data in Soneka with attributes. Segment audiences, personalise messages, and drive flows with typed contact fields.

Attributes are the structured data fields Soneka attaches to every contact and conversation. Think of them as columns in a CRM — but live, syncable, and usable inside every message, broadcast, flow, and AI agent you build. Instead of storing customer context in spreadsheets or scattered notes, attributes let your team, your automations, and your AI reference the same source of truth in real time.

<Frame>
  <img src="https://mintcdn.com/soneka-africa/XXyrTGYVNgSvQUD1/images/image-17.png?fit=max&auto=format&n=XXyrTGYVNgSvQUD1&q=85&s=1ddc326c60c77117e47881ec71c24793" alt="Image" width="1882" height="746" data-path="images/image-17.png" />
</Frame>

## Who It's For

Attributes are for any team that wants to move beyond generic broadcasts and support. E-commerce teams use them to store `last_order_id` and `lifetime_value`. Healthcare clinics store `appointment_date` and `insurance_provider`. SaaS companies track `plan_tier` and `trial_expires_at`. If you've ever wished a WhatsApp message could say more than "Hi {{name}}", attributes are the answer.

***

## Attribute Types

Every attribute in Soneka has a fixed data type. Choosing the right type unlocks validation, filtering, and formatting for that field everywhere it's used.

<CardGroup cols={2}>
  <Card title="Text" icon="font">
    Free-form strings up to 500 characters. Best for names, addresses, notes, or any unstructured value.
  </Card>

  <Card title="Number" icon="hashtag">
    Integers or decimals. Supports arithmetic in flows (e.g., `cart_value > 5000`) and formatting in messages.
  </Card>

  <Card title="Date" icon="calendar">
    ISO 8601 dates and datetimes. Enables relative filters like "expires in 7 days" and timezone-aware scheduling.
  </Card>

  <Card title="Boolean" icon="toggle-on">
    True/false flags. Ideal for `opted_in`, `vip`, `has_paid`, or any binary state you branch on.
  </Card>

  <Card title="List" icon="list">
    Predefined single-select or multi-select options (e.g., `plan_tier: [free, pro, enterprise]`). Guarantees consistent values.
  </Card>

  <Card title="URL" icon="link">
    Validated links. Auto-formats as clickable in the inbox and passes safely into template buttons.
  </Card>
</CardGroup>

<Tip>
  Types are enforced at write time. If a flow tries to save `"tomorrow"` into a Date attribute, Soneka rejects the write and logs the error rather than silently corrupting your data.
</Tip>

***

## System vs Custom Attributes

Soneka ships with a set of **system attributes** that are populated automatically, and lets you define unlimited **custom attributes** for anything specific to your business.

| Category           | Examples                                                                        | Editable  |
| ------------------ | ------------------------------------------------------------------------------- | --------- |
| System — Identity  | `name`, `phone`, `email`, `locale`, `timezone`                                  | Partial   |
| System — Lifecycle | `created_at`, `last_seen_at`, `last_message_at`, `opt_in_status`                | Read-only |
| System — Channel   | `whatsapp_id`, `profile_picture_url`, `channel_source`                          | Read-only |
| Custom             | Anything you define — e.g., `loyalty_points`, `preferred_language`, `nps_score` | Full      |

System attributes are guaranteed to exist on every contact. Custom attributes are optional per contact — a missing value returns `null` rather than an error, and you can set fallbacks in templates.

***

## Creating a Custom Attribute

<Steps>
  <Step title="Open the Attributes Library">
    Navigate to **Settings → Contacts → Attributes**. You'll see all existing system and custom attributes, along with their types and usage counts.
  </Step>

  <Step title="Click New Attribute">
    In the top-right, click **+ New Attribute**. Give it a **name** (lowercase, snake\_case is recommended — e.g., `last_order_total`) and a human-friendly **label** (e.g., "Last Order Total").
  </Step>

  <Step title="Pick a Type">
    Select one of the six types above. For **List**, add each allowed option on its own line. For **Number**, choose whether to allow decimals.
  </Step>

  <Step title="Set a Default Value (Optional)">
    Provide a default that Soneka assigns when a new contact is created without an explicit value. Useful for flags like `opted_in: false`.
  </Step>

  <Step title="Choose Visibility">
    Decide whether agents can edit this attribute from the inbox, or whether it's system-managed by flows and integrations only. Locking sensitive attributes (like `lifetime_value`) prevents accidental edits.
  </Step>

  <Step title="Save">
    Click **Create Attribute**. The field is now available across broadcasts, flows, templates, AI agents, and the inbox sidebar.
  </Step>
</Steps>

<Warning>
  Renaming an attribute updates its label everywhere, but the underlying key stays the same. Deleting an attribute is permanent and removes the value from every contact — export first if you might need it back.
</Warning>

***

## Populating Attribute Values

Attributes are only useful if they're kept fresh. Soneka gives you five ways to write values, and most teams use a combination.

<AccordionGroup>
  <Accordion title="Manual edits in the inbox" icon="pen">
    Any agent with permission can update attributes from the contact sidebar during a conversation. Great for ad-hoc updates like address changes or preferences captured verbally.
  </Accordion>

  <Accordion title="Flow Builder actions" icon="diagram-project">
    The **Set Attribute** node writes a value at any step in a flow. Combine with **Ask Question** nodes to collect data conversationally — e.g., ask for the customer's city, then save it into `city`.
  </Accordion>

  <Accordion title="CSV import" icon="file-csv">
    Bulk-update thousands of contacts by uploading a CSV. Soneka matches on `phone` and updates only the columns you include, leaving other attributes untouched.
  </Accordion>

  <Accordion title="API / webhooks" icon="code">
    POST to `/v1/contacts/{id}/attributes` to sync from your CRM, e-commerce platform, or data warehouse. Ideal for real-time updates like `last_order_id` after checkout.
  </Accordion>

  <Accordion title="Integrations" icon="plug">
    Shopify, WooCommerce, and Google Sheets integrations map source fields to Soneka attributes automatically. Set the mapping once and updates flow both ways.
  </Accordion>
</AccordionGroup>

***

## Using Attributes in Messages

Attributes drop into any message using double-brace syntax: `{{attribute_name}}`. Soneka validates references at send time and warns you if a template uses an attribute that doesn't exist.

<CodeGroup>
  ```text Broadcast theme={null}
  Hi {{name}}, your {{plan_tier}} plan renews on {{renewal_date}}. Reply STOP to opt out.
  ```

  ```text Flow reply theme={null}
  Welcome back, {{name}}! Your last order (#{{last_order_id}}) shipped on {{last_order_shipped_at}}.
  ```

  ```text Template variable theme={null}
  {{1}} → contact.name
  {{2}} → contact.appointment_date
  ```
</CodeGroup>

### Fallbacks

If an attribute might be missing, provide a fallback with the pipe syntax so the message never renders as an awkward blank:

```text theme={null}
Hi {{name|there}}, thanks for reaching out!
```

If `name` is empty, the message renders as "Hi there, thanks for reaching out!".

***

## Segmenting with Attributes

Every attribute becomes a filter you can layer in the **Audience Builder** for broadcasts and flow entry points. Filters combine with AND/OR logic and support ranges, list membership, and "exists / doesn't exist" checks.

| Operator                     | Works with   | Example                              |
| ---------------------------- | ------------ | ------------------------------------ |
| `equals` / `not equals`      | All types    | `plan_tier equals pro`               |
| `contains` / `starts with`   | Text         | `email contains @gmail.com`          |
| `greater than` / `less than` | Number, Date | `lifetime_value greater than 10000`  |
| `is in` / `not in`           | List         | `city is in [Nairobi, Lagos, Accra]` |
| `within last N days`         | Date         | `last_seen_at within last 30 days`   |
| `is set` / `is not set`      | All types    | `nps_score is not set`               |

Saved segments update in real time — when a contact's attributes change, they enter or leave segments automatically without a re-run.

***

## Attributes and AI Agents

AI agents read attributes as part of their context on every reply. This means an agent can greet a returning customer by name, quote the correct plan tier, or refuse to discuss billing with a contact whose `verified` flag is false — all without you writing custom prompts for each case.

<Tip>
  When designing an AI agent, list the exact attributes it should reference in the **System Prompt**. This prevents hallucination and keeps replies grounded in your real data.
</Tip>

***

## Best Practices

* **Name attributes for their meaning, not their source.** `customer_city` beats `shopify_city` — you may swap sources later.
* **Prefer List types over free-text where possible.** Consistent values make segments and analytics reliable.
* **Use booleans for state, not text.** `is_vip: true` is faster to filter than `vip_status: "yes"`.
* **Lock down financial and PII attributes.** Restrict edit access to admins and integrations only.
* **Set defaults for opt-in flags.** Never leave `opted_in` as `null` — it should always be `true` or `false`.
* **Archive unused attributes quarterly.** Fewer fields means faster imports and cleaner UX for agents.

***

## Limits

| Item                                    | Limit          |
| --------------------------------------- | -------------- |
| Custom attributes per workspace         | 250            |
| Attribute name length                   | 64 characters  |
| Text value length                       | 500 characters |
| List options per attribute              | 100            |
| Attribute writes per contact per minute | 60             |

Need more? Enterprise plans lift these ceilings — [contact support](/help/contact-support) to discuss your use case.
