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

# Profiles

> Create, upsert, update, look up and blacklist contacts.

Profiles are contacts. Every write is confined to your workspace by row-level security, and every consent change is logged. All endpoints authenticate with the [`X-Sender-Tenant` + `X-API-Key`](/en/api-reference/authentication) headers.

## The profile object

<ResponseField name="id" type="string">Contact UUID.</ResponseField>

<ResponseField name="email" type="string" />

<ResponseField name="phone" type="string" />

<ResponseField name="firstName" type="string" />

<ResponseField name="lastName" type="string" />

<ResponseField name="timezone" type="string" />

<ResponseField name="locale" type="string" />

<ResponseField name="emailConsent" type="string">`subscribed` / `unsubscribed` / `never_subscribed` / `cleaned`.</ResponseField>

<ResponseField name="smsConsent" type="string" />

<ResponseField name="pushConsent" type="string" />

<ResponseField name="emailConsentTimestamp" type="string" />

<ResponseField name="smsConsentTimestamp" type="string" />

<ResponseField name="pushConsentTimestamp" type="string" />

<ResponseField name="emailValidationState" type="string" />

<ResponseField name="customProperties" type="object" />

<ResponseField name="tags" type="string[]" />

<ResponseField name="rfmTier" type="string" />

<ResponseField name="notes" type="string" />

<ResponseField name="emailSuppressed" type="boolean" />

<ResponseField name="createdAt" type="string" />

<ResponseField name="updatedAt" type="string" />

## List profiles

```http theme={null}
GET /api/v1/public/profiles
```

<ParamField query="limit" type="integer" default="50">Page size 1–100.</ParamField>
<ParamField query="offset" type="integer" default="0">Records to skip.</ParamField>
<ParamField query="page" type="integer">1-based page (alternative to offset).</ParamField>
<ParamField query="search" type="string">Free-text search (max 255).</ParamField>
<ParamField query="segmentId" type="string">Filter to a segment (UUID).</ParamField>
<ParamField query="consent" type="string">`subscribed` / `unsubscribed` / `never_subscribed` / `cleaned`.</ParamField>
<ParamField query="channel" type="string">`email` or `sms`.</ParamField>
<ParamField query="sort" type="string">Sort key, e.g. `-createdAt`, `-updatedAt`.</ParamField>

Returns a [paginated](/en/api-reference/pagination) list of profile objects.

## Get a profile by email

```http theme={null}
GET /api/v1/public/profiles/lookup?email=dana@example.com
```

<ParamField query="email" type="string" required>The email to look up.</ParamField>

Returns the profile object, or `404 Profile not found`.

## Get a profile by ID

```http theme={null}
GET /api/v1/public/profiles/:id
```

Returns the profile object.

## Create a profile

```http theme={null}
POST /api/v1/public/profiles
```

<ParamField body="email" type="string">Max 320.</ParamField>
<ParamField body="phone" type="string">Max 32.</ParamField>
<ParamField body="firstName" type="string">Max 128.</ParamField>
<ParamField body="lastName" type="string">Max 128.</ParamField>
<ParamField body="timezone" type="string">Max 64.</ParamField>
<ParamField body="locale" type="string">Max 10.</ParamField>
<ParamField body="emailConsent" type="string">Consent enum.</ParamField>
<ParamField body="smsConsent" type="string">Consent enum.</ParamField>
<ParamField body="pushConsent" type="string">Consent enum.</ParamField>
<ParamField body="emailConsentSource" type="string">Max 64.</ParamField>
<ParamField body="smsConsentSource" type="string">Max 64.</ParamField>
<ParamField body="pushConsentSource" type="string">Max 64.</ParamField>

<ParamField body="tags" type="string[]" />

<ParamField body="customProperties" type="object" />

<ParamField body="notes" type="string">Max 4000, or null.</ParamField>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.senderz.app/api/v1/public/profiles \
    -H "X-Sender-Tenant: your-workspace-slug" \
    -H "X-API-Key: your-api-key" \
    -H "Content-Type: application/json" \
    -d '{
      "email": "dana@example.com",
      "firstName": "Dana",
      "emailConsent": "subscribed",
      "emailConsentSource": "api",
      "tags": ["newsletter"]
    }'
  ```
</CodeGroup>

## Upsert a profile

```http theme={null}
PUT /api/v1/public/profiles
```

Same body as **create**. Matches an existing contact by **email or phone** and creates one if none matches. Requires at least one of `email` / `phone`.

## Update a profile by email

```http theme={null}
PATCH /api/v1/public/profiles
```

The email is a **lookup key** — it isn't rewritten unless you pass `newEmail`. Returns `404` if the email isn't found.

<ParamField body="email" type="string" required>Lookup key (max 320).</ParamField>
<ParamField body="newEmail" type="string">Rename the contact's email.</ParamField>

<ParamField body="phone" type="string" />

<ParamField body="firstName" type="string" />

<ParamField body="lastName" type="string" />

<ParamField body="timezone" type="string" />

<ParamField body="locale" type="string" />

<ParamField body="emailConsent" type="string">Consent enum.</ParamField>
<ParamField body="smsConsent" type="string">Consent enum.</ParamField>
<ParamField body="pushConsent" type="string">Consent enum.</ParamField>

<ParamField body="tags" type="string[]" />

<ParamField body="customProperties" type="object" />

<ParamField body="notes" type="string">Max 4000, or null.</ParamField>

<ParamField body="city" type="string" />

<ParamField body="country" type="string" />

<ParamField body="stateProvince" type="string" />

<ParamField body="zip" type="string" />

<ParamField body="address1" type="string" />

<ParamField body="address2" type="string" />

<ParamField body="dateOfBirth" type="string" />

<ParamField body="gender" type="string" />

<ParamField body="jobTitle" type="string" />

<Info>
  Address-style fields (city, country, zip, DOB, gender, job title) merge into
  `customProperties` — they aren't native columns.
</Info>

## Update a profile by ID

```http theme={null}
PATCH /api/v1/public/profiles/:id
```

Same field set as create, addressed by UUID.

## Blacklist

```http theme={null}
POST /api/v1/public/profiles/blacklist
DELETE /api/v1/public/profiles/blacklist
```

<ParamField body="email" type="string">Required unless `contactId` is given.</ParamField>
<ParamField body="contactId" type="string">Contact UUID.</ParamField>
<ParamField body="channel" type="string">`email`, `sms`, or `both`.</ParamField>

`POST` suppresses the contact on the channel; `DELETE` lifts it. Both return the profile object.
