---
title: "Update this user's notification switches"
method: PUT
path: "/notifications/preferences/"
tags: ["notifications"]
---

# Update this user's notification switches

`PUT /notifications/preferences/`

## Request

- Base URL: `https://api.getoneprofile.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.getoneprofile.ai/notifications/preferences/`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

## Request body

- NotificationPreferencesPutSchema
  - `preferences` NotificationPreferenceSchema[], required
    - `email_enabled` boolean, required
    - `notification_kind` 'new_reply' | 'thread_labeled' | 'mailbox_disconnected' | 'low_credits' | 'credits_exhausted' | 'work_paused' | 'draft_awaiting_approval' | 'linkedin_checkpoint' | 'linkedin_browser_offline' | 'search_matches_waiting' | 'reply_sent_by_agent' | 'agent_sending_paused' | 'contact_asked_to_stop' | 'affiliate_welcome' | 'affiliate_referral_signed_up' | 'affiliate_referral_converted' | 'affiliate_statement' | 'affiliate_payout_sent' | 'affiliate_action_needed' | 'affiliate_balance_forfeited', required: Everything the product can tell a human about. THREAD_LABELED is the only kind that carries a label. The rest are workspace events with no label dimension, which is why the rule table constrains ``label_id`` to exactly this kind. The three credit kinds are stored separately even though the settings UI offers one "credit alerts" switch: they crossed three different thresholds and keeping them apart means splitting the switch later is a UI change, not a migration. The ``affiliate_*`` kinds are program mail to the enrolled affiliate's contact address, not workspace-member fan-out: they carry no preference switch, and the settings grid on the dashboard skips them by prefix. SEARCH_MATCHES_WAITING: a scheduled lead search no longer buys its rows, so when it fires and finds new matches the buy waits on a person as a proposal, and this is how they hear about it.

## Response `200`

Successful Response

- NotificationPreferenceSchema[]
  - `email_enabled` boolean, required
  - `notification_kind` 'new_reply' | 'thread_labeled' | 'mailbox_disconnected' | 'low_credits' | 'credits_exhausted' | 'work_paused' | 'draft_awaiting_approval' | 'linkedin_checkpoint' | 'linkedin_browser_offline' | 'search_matches_waiting' | 'reply_sent_by_agent' | 'agent_sending_paused' | 'contact_asked_to_stop' | 'affiliate_welcome' | 'affiliate_referral_signed_up' | 'affiliate_referral_converted' | 'affiliate_statement' | 'affiliate_payout_sent' | 'affiliate_action_needed' | 'affiliate_balance_forfeited', required: Everything the product can tell a human about. THREAD_LABELED is the only kind that carries a label. The rest are workspace events with no label dimension, which is why the rule table constrains ``label_id`` to exactly this kind. The three credit kinds are stored separately even though the settings UI offers one "credit alerts" switch: they crossed three different thresholds and keeping them apart means splitting the switch later is a UI change, not a migration. The ``affiliate_*`` kinds are program mail to the enrolled affiliate's contact address, not workspace-member fan-out: they carry no preference switch, and the settings grid on the dashboard skips them by prefix. SEARCH_MATCHES_WAITING: a scheduled lead search no longer buys its rows, so when it fires and finds new matches the buy waits on a person as a proposal, and this is how they hear about it.

## Other responses

- `401`: Unauthorized
- `403`: Forbidden
- `422`: Invalid request made to the API.
- `500`: Internal server error.
- `502`: Bad gateway error.
- `503`: Service unavailable.

---

[API](https://skmtc.dev/getoneprofile/apis/api-reference-oneprofile.md) · [All operations](https://skmtc.dev/getoneprofile/apis/api-reference-oneprofile/llms.txt) · [OpenAPI document](https://skmtc.dev/getoneprofile/apis/api-reference-oneprofile/revisions/4a6bd71e3f02?raw)
