Push devices and settings
View and change users' push settings and conversation Do Not Disturb, or troubleshoot their push devices, from your server. For what Do Not Disturb and preview modes do, see Offline push.
| You want to | API |
|---|---|
| Sync with your app's "Do Not Disturb" or "show sender only" switches | Update push settings |
| Sync with your app's "mute this group" setting | Set conversation Do Not Disturb, Remove conversation Do Not Disturb |
| Troubleshoot a user not getting pushes | List push devices, then see Troubleshooting missing pushes |
| A phone that switched accounts still gets the previous account's pushes | Unbind a push device |
For example, turn on 8 hours of Do Not Disturb for alice:
curl -X PATCH "$IM_API/$ORG/$APP/users/alice/push-settings" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "dnd": { "duration_seconds": 28800 } }'- One set of settings shared with clients: users change the same settings from clients, and the last change wins.
- Devices are notified of changes: when push settings or conversation Do Not Disturb change, all the user's online devices get
push.settings_changedand update their local copy. Changes that change nothing (changedfalse) aren't notified. - Version: push settings and conversation Do Not Disturb share one version,
settings_version, incremented when anything changes; clients use it to tell whether their local settings are current. - User status: APIs return
404 not_foundwhen the user doesn't exist or was deleted; deleting a user deletes their push settings, conversation Do Not Disturb and push devices. Banned users' settings are kept, but their push devices lapse with their sign-ins. - These APIs only count toward the app's OpenAPI quota and all work while the app is read-only.
Get push settings
/{org_name}/{app_name}/users/{username}/push-settingsPath parameters
For org_name and app_name, see the server overview.
| Parameter | Type | Description |
|---|---|---|
username | String | The username |
Request example
curl "$IM_API/$ORG/$APP/users/zhangsan/push-settings" \
-H "Authorization: Bearer $APP_TOKEN"Response
On success you get 200 OK with a push settings object. For a user who never set anything:
{
"dnd": null,
"quiet_hours": null,
"preview": null,
"effective_preview": "full",
"settings_version": 0
}Errors
| HTTP status | code | Description |
|---|---|---|
| 404 | not_found | The user doesn't exist or was deleted |
Update push settings
Change a user's global Do Not Disturb, quiet hours and preview mode. Send only the fields to change; others stay as they are.
- Settings equal to the current ones don't count as a change:
changedisfalseand the version doesn't move. Turning global Do Not Disturb on again for the same duration (end times within 1 minute of each other) doesn't count either, and the end time stays. - Global Do Not Disturb durations start from this call and end automatically; the user's devices aren't notified separately when it ends.
/{org_name}/{app_name}/users/{username}/push-settingsPath parameters
For org_name and app_name, see the server overview.
| Parameter | Type | Description |
|---|---|---|
username | String | The username |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
dnd | Object | No | Global Do Not Disturb. null turns it off; { "duration_seconds": 28800 } turns it on for a while, 1 to 315360000 seconds (10 years); { "duration_seconds": null } or {} turns it on indefinitely |
quiet_hours | Object | No | Quiet hours. null turns them off; otherwise start, end and timezone, all required: start and end are times in HH:MM (24-hour, two digits, such as 07:30), not equal, with end earlier than start meaning across midnight; timezone is an IANA time zone name such as Asia/Shanghai, not forms like GMT+8 |
preview | String | No | Preview mode: full sender and content, sender_only only the sender, none neither; null clears the user's choice so push_default_preview from the runtime policy applies |
Request example
Turn on 8 hours of global Do Not Disturb, set quiet hours from 22:00 to 07:30, and show only the sender in notifications:
curl -X PATCH "$IM_API/$ORG/$APP/users/zhangsan/push-settings" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"dnd": { "duration_seconds": 28800 },
"quiet_hours": { "start": "22:00", "end": "07:30", "timezone": "Asia/Shanghai" },
"preview": "sender_only"
}'Response
On success you get 200 OK with the updated push settings object plus changed, whether anything changed.
{
"dnd": { "until": "2026-10-05T03:20:47.124Z" },
"quiet_hours": { "start": "22:00", "end": "07:30", "timezone": "Asia/Shanghai" },
"preview": "sender_only",
"effective_preview": "sender_only",
"settings_version": 1,
"changed": true
}Errors
| HTTP status | code | Description |
|---|---|---|
| 400 | invalid_argument | details.reason invalid_duration: the duration isn't between 1 and 315360000 seconds |
| 400 | invalid_argument | details.reason invalid_quiet_hours: a time has the wrong format, or start equals end |
| 400 | invalid_argument | details.reason invalid_timezone: the time zone isn't an IANA name |
| 400 | invalid_argument | details.reason invalid_preview: the preview mode isn't full, sender_only or none |
| 400 | invalid_argument | No details.reason: the body has an unknown field, or dnd is neither an object nor null; details.field names the field |
| 404 | not_found | The user doesn't exist or was deleted |
List conversation Do Not Disturb
List the one-to-one chats and groups a user has muted. Expired settings and one-to-one chats whose other user was deleted aren't returned, so a page may have fewer than limit items; rely only on next_cursor.
/{org_name}/{app_name}/users/{username}/push-settings/conversationsPath parameters
For org_name and app_name, see the server overview.
| Parameter | Type | Description |
|---|---|---|
username | String | The username |
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | Number | No | Page size, 1 to 500, default 100 |
cursor | String | No | The cursor for the next page, from the previous page's next_cursor; omit for the first page |
known_version | Number | No | First page only: the settings_version you saved. If it equals the current version, only not_modified true and the version are returned, with empty items |
Request example
curl "$IM_API/$ORG/$APP/users/zhangsan/push-settings/conversations?limit=100" \
-H "Authorization: Bearer $APP_TOKEN"Response
On success you get 200 OK:
| Field | Type | Description |
|---|---|---|
settings_version | Number | The current version; 0 if never set |
not_modified | Boolean | true when the first page's known_version equals the current version |
items | Array<Object> | Conversation Do Not Disturb settings, each a conversation Do Not Disturb object, sorted by conversation type (group first) and conversation |
next_cursor | String | The next page's cursor; an empty string when there's no next page |
{
"settings_version": 4,
"not_modified": false,
"items": [
{
"conversation_type": "group",
"target": "100311272729346048",
"mode": "mention_only",
"until": null,
"updated_at": "2026-10-04T19:21:19.963Z"
},
{
"conversation_type": "single",
"target": "lisi",
"mode": "none",
"until": "2026-10-05T19:21:20.019Z",
"updated_at": "2026-10-04T19:21:20.022Z"
}
],
"next_cursor": ""
}Errors
| HTTP status | code | Description |
|---|---|---|
| 400 | invalid_argument | limit isn't between 1 and 500, known_version isn't a non-negative integer, or cursor is invalid |
| 404 | not_found | The user doesn't exist or was deleted |
Set conversation Do Not Disturb
Set Do Not Disturb for one of a user's one-to-one chats or groups, overwriting any existing setting with this mode and duration. Setting the same mode and duration again (end times within 1 minute of each other, or both indefinite) returns changed false and keeps the end time.
For groups, the user must be a member. When they leave or are removed, the group's setting is deleted, so rejoining starts with normal pushes.
/{org_name}/{app_name}/users/{username}/push-settings/conversations/single/{peer}/{org_name}/{app_name}/users/{username}/push-settings/conversations/group/{group_id}Path parameters
For org_name and app_name, see the server overview.
| Parameter | Type | Description |
|---|---|---|
username | String | The username |
peer | String | The other user in the one-to-one chat; not the user themself |
group_id | String | The group ID |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
mode | String | Yes | none pushes nothing from this conversation; mention_only pushes only when the user is mentioned, groups only |
duration_seconds | Number | No | Duration in seconds, 1 to 315360000 (10 years), from this call; normal pushes resume when it ends. Omitted or null means indefinite |
Request example
Only push group messages that mention the user:
curl -X PUT "$IM_API/$ORG/$APP/users/zhangsan/push-settings/conversations/group/100311272729346048" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"mode": "mention_only"
}'No pushes from the one-to-one chat with lisi for 1 day:
curl -X PUT "$IM_API/$ORG/$APP/users/zhangsan/push-settings/conversations/single/lisi" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"mode": "none",
"duration_seconds": 86400
}'Response
On success you get 200 OK with the conversation Do Not Disturb object plus changed (whether anything changed) and settings_version (the version after setting).
{
"conversation_type": "single",
"target": "lisi",
"mode": "none",
"until": "2026-10-05T19:21:20.019Z",
"updated_at": "2026-10-04T19:21:20.022Z",
"changed": true,
"settings_version": 4
}Errors
| HTTP status | code | Description |
|---|---|---|
| 400 | invalid_argument | details.reason invalid_mode: mode is missing or invalid, or mention_only was set for a one-to-one chat |
| 400 | invalid_argument | details.reason invalid_duration: the duration isn't between 1 and 315360000 seconds |
| 400 | invalid_argument | details.reason self_conversation: the one-to-one peer is the user themself |
| 403 | not_group_member | The user isn't a member of the group, or the group was dissolved |
| 404 | not_found | The user or one-to-one peer doesn't exist or was deleted; the group doesn't exist |
| 409 | limit_exceeded | details.reason conversation_setting_limit: the user already has 10000 conversation Do Not Disturb settings |
Remove conversation Do Not Disturb
Remove a user's Do Not Disturb for one one-to-one chat or group so normal pushes resume. If it was never set (or already ended), you still get success with changed false, so retries are safe. Removing group settings doesn't check membership, so it works even if the group doesn't exist or the user left.
/{org_name}/{app_name}/users/{username}/push-settings/conversations/single/{peer}/{org_name}/{app_name}/users/{username}/push-settings/conversations/group/{group_id}Path parameters
For org_name and app_name, see the server overview.
| Parameter | Type | Description |
|---|---|---|
username | String | The username |
peer | String | The other user in the one-to-one chat |
group_id | String | The group ID |
Request example
curl -X DELETE "$IM_API/$ORG/$APP/users/zhangsan/push-settings/conversations/single/lisi" \
-H "Authorization: Bearer $APP_TOKEN"Response
On success you get 200 OK:
| Field | Type | Description |
|---|---|---|
changed | Boolean | Whether an active setting was removed |
settings_version | Number | The version after removal |
{
"changed": true,
"settings_version": 5
}Errors
| HTTP status | code | Description |
|---|---|---|
| 400 | invalid_argument | details.reason self_conversation: the one-to-one peer is the user themself |
| 404 | not_found | The user or one-to-one peer doesn't exist or was deleted |
List push devices
List the devices and tokens a user registered for push, by ascending session_id. Each device is one of the user's sign-ins, with the same session_id as in List devices; signed-in devices that didn't register push (including Web and other platforms that can't, and devices whose user turned off notifications) aren't included. The number is bounded by the device limit, so there's no paging.
/{org_name}/{app_name}/users/{username}/push-devicesPath parameters
For org_name and app_name, see the server overview.
| Parameter | Type | Description |
|---|---|---|
username | String | The username |
Request example
curl "$IM_API/$ORG/$APP/users/zhangsan/push-devices" \
-H "Authorization: Bearer $APP_TOKEN"Response
On success you get 200 OK. items holds the registered devices, each a push device object; empty if there are none.
{
"items": [
{
"session_id": "100310865395318784",
"device_id": "5f0c2a9e-7d1b-4c7e-9a51-2f6d0f3b8c11",
"platform": "ios",
"language": "zh-Hans-CN",
"tokens": [
{ "kind": "alert", "priority": 1, "credential": "ios-prod", "channel": "apns", "token": "6abf38…f665" },
{ "kind": "voip", "priority": 1, "credential": "ios-prod", "channel": "apns", "token": "13b7b7…32c0" }
],
"badge": 6,
"login_at": "2026-10-04T19:19:33.998Z",
"updated_at": "2026-10-04T19:19:48.452Z"
},
{
"session_id": "100310865730863104",
"device_id": "a3d91c07-58e2-4f6b-b1c4-7e0f2d9a6c35",
"platform": "android",
"language": "zh-CN",
"tokens": [
{ "kind": "alert", "priority": 1, "credential": "xiaomi-main", "channel": "xiaomi", "token": "Lx9Qw2…Kd3P" },
{ "kind": "alert", "priority": 2, "credential": "fcm-global", "channel": "fcm", "token": "cR5tY8…nM0q" }
],
"badge": 0,
"login_at": "2026-10-04T19:19:34.079Z",
"updated_at": "2026-10-04T19:27:20.056Z"
}
]
}Errors
| HTTP status | code | Description |
|---|---|---|
| 404 | not_found | The user doesn't exist or was deleted |
Unbind a push device
Delete the push registration of one of a user's devices, so that device stops getting this user's offline pushes.
- It only unbinds push, not the sign-in: the device stays signed in and push resumes the next time the app starts or registers. To stop pushes for good, sign out that device or ban the user.
- If the device has no push registration (including one already unbound), you get
404 not_found, which you can treat as success when retrying. - The user's devices aren't notified.
/{org_name}/{app_name}/users/{username}/push-devices/{session_id}Path parameters
For org_name and app_name, see the server overview.
| Parameter | Type | Description |
|---|---|---|
username | String | The username |
session_id | String | The device's session ID, from session_id in List push devices |
Request example
curl -X DELETE "$IM_API/$ORG/$APP/users/zhangsan/push-devices/100310865730863104" \
-H "Authorization: Bearer $APP_TOKEN"Response
On success you get 204 No Content with no body.
Errors
| HTTP status | code | Description |
|---|---|---|
| 404 | not_found | The user doesn't exist or was deleted; the device has no push registration, was already unbound, or belongs to another user |
Data structures
Push settings object
| Field | Type | Description |
|---|---|---|
dnd | Object | Global Do Not Disturb; null when off or ended. until is the end time, null for indefinite |
quiet_hours | Object | Quiet hours; null when not set. start and end are times (HH:MM, 24-hour), with end earlier than start meaning across midnight, start included and end not; timezone is the IANA time zone used |
preview | String | The user's chosen preview mode: full, sender_only or none; null if not chosen |
effective_preview | String | The preview mode in effect: the user's choice if any, otherwise push_default_preview from the runtime policy |
settings_version | Number | The version shared by push settings and conversation Do Not Disturb, incremented on any change; 0 if never set |
{
"dnd": { "until": null },
"quiet_hours": { "start": "22:00", "end": "07:30", "timezone": "Asia/Shanghai" },
"preview": "sender_only",
"effective_preview": "sender_only",
"settings_version": 2
}Conversation Do Not Disturb object
| Field | Type | Description |
|---|---|---|
conversation_type | String | single or group |
target | String | The other user for one-to-one, the group ID for groups |
mode | String | none no pushes; mention_only only when the user is mentioned (groups only) |
until | String | When it ends; null for indefinite |
updated_at | String | When it was last set |
{
"conversation_type": "group",
"target": "100311272729346048",
"mode": "mention_only",
"until": null,
"updated_at": "2026-10-04T19:21:19.963Z"
}Push device object
| Field | Type | Description |
|---|---|---|
session_id | String | The device's session ID, the same as session_id in the device object |
device_id | String | Device ID, submitted by the client at sign-in |
platform | String | ios, macos, android or harmony |
language | String | The language the device registered (BCP 47), used to pick template languages; null if none, in which case push_default_language from the runtime policy is used |
tokens | Array<Object> | The device's push tokens, regular tokens first in priority order and the VoIP token last; fields below |
badge | Number | The device's current badge count: the value the app last reported plus pushes since |
login_at | String | When this sign-in happened |
updated_at | String | When the push registration was last updated; every registration by the app updates it |
Fields of each item in tokens:
| Field | Type | Description |
|---|---|---|
kind | String | alert regular token; voip VoIP token, iOS calls only |
priority | Number | Priority of regular tokens, from 1, with lower numbers used first; 1 for VoIP tokens |
credential | String | The credential name the token belongs to; an empty string when the credential was deleted and the token not yet cleaned up |
channel | String | apns, fcm, huawei, harmony, xiaomi, oppo, vivo, honor or meizu |
token | String | The masked token: only the first 6 and last 4 characters, with … in between |
{
"session_id": "100310865730863104",
"device_id": "a3d91c07-58e2-4f6b-b1c4-7e0f2d9a6c35",
"platform": "android",
"language": "zh-CN",
"tokens": [
{ "kind": "alert", "priority": 1, "credential": "xiaomi-main", "channel": "xiaomi", "token": "Lx9Qw2…Kd3P" },
{ "kind": "alert", "priority": 2, "credential": "fcm-global", "channel": "fcm", "token": "cR5tY8…nM0q" }
],
"badge": 0,
"login_at": "2026-10-04T19:19:34.079Z",
"updated_at": "2026-10-04T19:27:20.056Z"
}