Notification Preferences

The notification preference object

Attribute Type Description
channels array Array of per-type, per-channel preferences. Contains one row for every supported notification type and channel pair, always in the same fixed order, with a type’s in_app row before its email row.
channels[].notification_type string Notification preference type.
channels[].channel string Delivery channel: in_app (the in-product feed and bell) or email.
channels[].enabled boolean Whether the channel is enabled for this notification type.
channels[].feed_type string The notification_type of the corresponding notification in GET /v2/notifications, or null when there is no corresponding notification type. null for occasional_updates and project_deleted. Both submitted-timesheet preferences share the timesheet_submitted feed type.
channels[].category string The category of the corresponding notification in GET /v2/notifications, or null when feed_type is null.
weekly_report object Weekly tracked-time email preference.
weekly_report.enabled boolean Whether the weekly tracked-time email is enabled.
approval_confirmation object Timesheet approval email preference.
approval_confirmation.enabled boolean Whether an email is sent when a timesheet is approved.
reminders object Daily reminder preferences.
reminders.enabled boolean Whether daily reminders are enabled.
reminders.time_of_day integer Time of day for reminders, as seconds after local midnight in the user’s timezone. Can range from 0 to 86399 (e.g. 59400 is 16:30).
reminders.days array Weekdays on which reminders are sent, as strings from monday through sunday.
reminders.via_desktop boolean Whether desktop and web-push reminders are enabled. This does not register a push subscription.
reminders.via_slack boolean Whether Slack reminders are enabled. The value is stored whether or not Slack is connected.
reminders.team_wide boolean Whether the user receives team-wide reminders.

Reminders sent by email and in the in-product feed are expressed through the channels array as the time_tracking_reminder type with the email and in_app channels. web_push_subscription is not part of this object.

Required permissions

Any authenticated user can read and update their own notification preferences, and no administrator role is required. There is no :id parameter: this endpoint always operates on the authenticated caller’s preferences. An inactive account returns a 403 Forbidden status code.

Retrieve notification preferences

Beta endpoint. Fully available, but the response shape may still change. Until it is frozen, every response includes Harvest-Api-Stability: beta.

Returns the notification preferences for the authenticated user.

GET /v2/notification_preferences

This endpoint takes no parameters.

Example Request:

curl "https://api.harvestapp.com/v2/notification_preferences" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Harvest-Account-Id: $ACCOUNT_ID" \
  -H "User-Agent: MyApp ([email protected])"

Example Response:

{
  "channels": [
    {
      "notification_type": "timesheet_submitted_person",
      "channel": "in_app",
      "enabled": true,
      "feed_type": "timesheet_submitted",
      "category": "timesheets"
    },
    {
      "notification_type": "timesheet_submitted_person",
      "channel": "email",
      "enabled": false,
      "feed_type": "timesheet_submitted",
      "category": "timesheets"
    },
    {
      "notification_type": "timesheet_submitted_project",
      "channel": "in_app",
      "enabled": true,
      "feed_type": "timesheet_submitted",
      "category": "timesheets"
    },
    {
      "notification_type": "timesheet_submitted_project",
      "channel": "email",
      "enabled": false,
      "feed_type": "timesheet_submitted",
      "category": "timesheets"
    },
    {
      "notification_type": "timesheet_approved",
      "channel": "in_app",
      "enabled": true,
      "feed_type": "timesheet_approved",
      "category": "timesheets"
    },
    "{18 more channel preference objects}",
    {
      "notification_type": "occasional_updates",
      "channel": "email",
      "enabled": true,
      "feed_type": null,
      "category": null
    }
  ],
  "weekly_report": {
    "enabled": true
  },
  "approval_confirmation": {
    "enabled": true
  },
  "reminders": {
    "enabled": true,
    "time_of_day": 59400,
    "days": [
      "monday",
      "tuesday",
      "wednesday",
      "thursday",
      "friday"
    ],
    "via_desktop": true,
    "via_slack": false,
    "team_wide": false
  }
}

Update notification preferences

Beta endpoint. Fully available, but the response shape may still change. Until it is frozen, every response includes Harvest-Api-Stability: beta.

Updates the authenticated user’s notification preferences. Every key is optional, and omitted keys keep their current value. Returns the preferences as they are after the update.

PATCH /v2/notification_preferences
Parameter Type Description
channels array of objects Preference entries in the form {notification_type: String, channel: "in_app" or "email", enabled: Boolean}. Supply at most one entry per type and channel pair. An empty array changes nothing.
channels[].notification_type string Notification preference type.
channels[].channel string Delivery channel: in_app or email.
channels[].enabled boolean Whether to enable the channel for this notification type.
weekly_report.enabled boolean Whether to enable the weekly tracked-time email.
approval_confirmation.enabled boolean Whether to enable the email sent when a timesheet is approved.
reminders.enabled boolean Whether to enable daily reminders.
reminders.time_of_day integer or numeric string Time of day for reminders, as seconds after local midnight in the user’s timezone. Can range from 0 to 86399.
reminders.days array of strings Weekdays on which to send reminders: monday through sunday. An empty array is invalid.
reminders.via_desktop boolean Whether to enable desktop and web-push reminders. Does not register a push subscription.
reminders.via_slack boolean Whether to enable Slack reminders. Stored whether or not Slack is connected.
reminders.team_wide boolean Whether to receive team-wide reminders.

Boolean values may be sent as true, false, "true", "false", "1", "0", 1, or 0. Null values are invalid. Unknown top-level keys are ignored.

Example Request:

curl -X PATCH "https://api.harvestapp.com/v2/notification_preferences" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Harvest-Account-Id: $ACCOUNT_ID" \
  -H "Content-Type: application/json" \
  -H "User-Agent: MyApp ([email protected])" \
  -d '{"channels": [{"notification_type": "timesheet_submitted_person", "channel": "email", "enabled": true}], "reminders": {"time_of_day": 59400}}'

Example Response:

{
  "channels": [
    {
      "notification_type": "timesheet_submitted_person",
      "channel": "in_app",
      "enabled": true,
      "feed_type": "timesheet_submitted",
      "category": "timesheets"
    },
    {
      "notification_type": "timesheet_submitted_person",
      "channel": "email",
      "enabled": true,
      "feed_type": "timesheet_submitted",
      "category": "timesheets"
    },
    {
      "notification_type": "timesheet_submitted_project",
      "channel": "in_app",
      "enabled": true,
      "feed_type": "timesheet_submitted",
      "category": "timesheets"
    },
    {
      "notification_type": "timesheet_submitted_project",
      "channel": "email",
      "enabled": false,
      "feed_type": "timesheet_submitted",
      "category": "timesheets"
    },
    {
      "notification_type": "timesheet_approved",
      "channel": "in_app",
      "enabled": true,
      "feed_type": "timesheet_approved",
      "category": "timesheets"
    },
    "{18 more channel preference objects}",
    {
      "notification_type": "occasional_updates",
      "channel": "email",
      "enabled": true,
      "feed_type": null,
      "category": null
    }
  ],
  "weekly_report": {
    "enabled": true
  },
  "approval_confirmation": {
    "enabled": true
  },
  "reminders": {
    "enabled": true,
    "time_of_day": 59400,
    "days": [
      "monday",
      "tuesday",
      "wednesday",
      "thursday",
      "friday"
    ],
    "via_desktop": true,
    "via_slack": false,
    "team_wide": false
  }
}

Update notification preferences with PUT

Beta endpoint. Fully available, but the response shape may still change. Until it is frozen, every response includes Harvest-Api-Stability: beta.

PUT /v2/notification_preferences accepts the same request body and behaves identically to PATCH: supplied keys are merged, and omitted keys keep their current value.

PUT /v2/notification_preferences

Example Request:

curl -X PUT "https://api.harvestapp.com/v2/notification_preferences" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Harvest-Account-Id: $ACCOUNT_ID" \
  -H "Content-Type: application/json" \
  -H "User-Agent: MyApp ([email protected])" \
  -d '{"weekly_report": {"enabled": false}}'

The response is the same preference object returned by PATCH /v2/notification_preferences.

Errors

Status Description
400 The User-Agent header is missing: {"message":"User-Agent header required"}.
401 The credentials are missing or invalid.
403 The account is inactive: {"message":"Account inactive"}.
409 Another request updated the preferences at the same time and the change was rolled back: {"message":"Notification preferences were updated concurrently; retry the request"}.
415 A request body was not sent as application/json: {"message":"Content-Type header required to be application/json, got …"}. When the header is absent, the message ends with got nil.
422 The request is malformed, or a well-formed value cannot be stored by the account. The response body contains a message that explains the rejection.

A 422 is returned for an unknown notification type (Unknown notification type "…"), an unsupported channel for a type (Unsupported notification channel "…" for "…"), a duplicate type and channel pair (Duplicate channel preference for "…"/"…"), a non-boolean value (… must be a boolean), an invalid weekday, an empty reminders.days array, or an out-of-range reminders.time_of_day. Multiple validation messages are joined with , .

A reminders.team_wide value is refused with a 422 when the account has no team-wide timesheet reminder: the message is This account has no team-wide timesheet reminder to opt out of when opting out, or This account has no team-wide timesheet reminder to opt into when opting in. Setting reminders.team_wide to the value already held succeeds without change.

Still have questions? We’re happy to help!

Contact Us