# Contacts and Consent (/docs/guides/contacts)

## Before You Begin [#before-you-begin]

Obtain a [brand-scoped API key](/docs/authentication) and set `SMOBI_API_KEY` in your server environment. Use a phone number you control when testing.

## Create or Update a Contact [#create-or-update-a-contact]

Contacts are upserted by phone number within your brand. Repeating the same upsert does not create another contact for that number.

```bash
curl --request POST 'https://api.smobi.com/v1/contacts' \
  --header "x-api-key: $SMOBI_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
    "phoneNumber": "15552223333",
    "firstName": "Alex",
    "tags": ["customer"],
    "customFields": { "plan": "standard" }
  }'
```

A new contact returns `201`; an existing contact update returns `200`. Save its `id`, or use its phone number in subsequent contact endpoints.

## Record Consent Accurately [#record-consent-accurately]

New contacts default to `UNKNOWN`. **Campaigns send only to `OPTED_IN` contacts.** Set `marketingConsent` to `OPTED_IN` only after collecting consent; this value records your confirmation that the contact agreed to receive marketing messages.

`OPTED_OUT` is always accepted. Trying to opt in a previously opted-out contact through the API returns `422`. The contact must opt back in through a supported channel, such as texting START. Do not work around suppression by recreating the contact.

## Update Attributes [#update-attributes]

`PATCH /v1/contacts/{identifier}` applies only supplied fields:

- Omit a field to leave it unchanged.
- Send `null` to clear a nullable scalar field.
- `tags` replaces the entire tag list.
- `customFields` merges keys; a `null` value deletes that key.
- `phoneNumber` is immutable.

Tags and custom fields can be used in segment rules. Store stable external IDs in `customFields` when linking Smobi contacts to your application.

## Bulk Sync [#bulk-sync]

`POST /v1/contacts/bulk` accepts a `contacts` array of up to **100** records. Results are reported per item, so inspect each result even when the HTTP request succeeds. Duplicate phone numbers within one batch reject the entire request with `400`.

## Read Every Page [#read-every-page]

`GET /v1/contacts` returns cursor pagination. Pass `pagination.nextCursor` as the next request's `cursor` until `hasMore` is false. Supported filters include `phoneNumber`, `email`, repeatable `tag`, and `status` (`active`, `archived`, or `all`). URL-encode cursor and filter values.

## Archive or Restore [#archive-or-restore]

`DELETE /v1/contacts/{identifier}` archives a contact and returns `204`. Archived contacts are hidden from default lists and excluded from campaigns and segment syncs. Repeat archiving is safe.

Restore with `PATCH {"active": true}`. Archiving preserves the contact record. Clearing nullable profile fields is a separate update and does not establish that all associated personal data has been deleted.

## Related Resources [#related-resources]

- [Contacts API Reference](/docs/api/contacts/upsert-contact)
- [Audiences and Campaigns](/docs/guides/campaigns)
