Mark a chat read or unread

PATCHhttps://api.wapito.com/v1/chats/{id}

Send a channel token on every request: Authorization: Bearer wpt_YOUR_TOKEN

Beta

Sets or clears the unread badge on a chat. Marking a chat unread is a purely local flag that does not notify the other side, which makes it a convenient way to hand a conversation back to a human operator from an automated workflow. Clearing it does not send read receipts; use the message read endpoint for that.

Parameters

NameInTypeRequiredDescriptionExample
idpathstringRequiredChat id, in any accepted recipient form.15551234567@s.whatsapp.net

Request body

Fields of the request body
FieldTypeRequiredDescription
unreadbooleanRequiredAlways `true`: marks the chat unread. Clearing the badge means reading the chat, which sends read receipts — use `PUT /messages/{id}/read` for that.
{
  "unread": true
}

Responses

200

The chat after the change.

Fields of the 200 response
FieldTypeRequiredDescription
archivedbooleanRequiredWhether the chat is archived.
idstringRequiredChat id (`@s.whatsapp.net`, `@g.us` or `@newsletter`).
last_messageobject | nullRequiredMost recent message in the chat, when the engine stores history.
audioobjectOptionalMedia attached to a message. `link` is a signed Wapito URL, not a WhatsApp CDN URL.
captionstring | nullRequiredCaption sent alongside the media.
errorstringOptionalSet to `unavailable` when the media could not be copied before it expired on the engine.one of unavailable
file_namestring | nullRequiredOriginal file name when the sender supplied one.
file_sizeinteger | nullRequiredSize in bytes.
idstring | nullRequiredWapito media id (`med_` + ULID), or `null` when the copy from the engine failed.
linkstring | nullRequiredSigned `/v1/media/{id}?exp&sig` URL, valid 24 h on sandbox and 7 days on premium.
mime_typestringRequiredIANA media type reported by WhatsApp.
chat_idstringRequiredChat the message belongs to, as `@s.whatsapp.net`, `@g.us` or `@newsletter`.
contactobjectOptionalContact card payload of a `contact` message.
vcardstringRequiredRaw vCard 3.0 text as WhatsApp stores it.
contextobjectOptionalReply, forward and mention context for a message.
forwardedbooleanRequiredWhether WhatsApp marked the message as forwarded.
mentionsarray of stringRequiredPhone numbers mentioned with @ in the body.
quoted_authorstring | nullRequiredSender of the quoted message.
quoted_idstring | nullRequiredId of the quoted message, when this message is a reply.
documentobjectOptionalMedia attached to a message. `link` is a signed Wapito URL, not a WhatsApp CDN URL.
captionstring | nullRequiredCaption sent alongside the media.
errorstringOptionalSet to `unavailable` when the media could not be copied before it expired on the engine.one of unavailable
file_namestring | nullRequiredOriginal file name when the sender supplied one.
file_sizeinteger | nullRequiredSize in bytes.
idstring | nullRequiredWapito media id (`med_` + ULID), or `null` when the copy from the engine failed.
linkstring | nullRequiredSigned `/v1/media/{id}?exp&sig` URL, valid 24 h on sandbox and 7 days on premium.
mime_typestringRequiredIANA media type reported by WhatsApp.
fromstring | nullRequiredSender in digits for direct chats, or the group id for group chats. `null` when only a LID is known.
from_lidstring | nullRequiredSender LID when WhatsApp addressed the message by LID rather than phone number.
from_mebooleanRequiredTrue when the channel sent the message, false when it received it.
from_namestring | nullRequiredPush name of the sender as WhatsApp reports it.
idstringRequiredEngine message id, unique within the channel.
imageobjectOptionalMedia attached to a message. `link` is a signed Wapito URL, not a WhatsApp CDN URL.
captionstring | nullRequiredCaption sent alongside the media.
errorstringOptionalSet to `unavailable` when the media could not be copied before it expired on the engine.one of unavailable
file_namestring | nullRequiredOriginal file name when the sender supplied one.
file_sizeinteger | nullRequiredSize in bytes.
idstring | nullRequiredWapito media id (`med_` + ULID), or `null` when the copy from the engine failed.
linkstring | nullRequiredSigned `/v1/media/{id}?exp&sig` URL, valid 24 h on sandbox and 7 days on premium.
mime_typestringRequiredIANA media type reported by WhatsApp.
locationobjectOptionalLocation payload of a `location` message.
addressstring | nullRequiredStreet address shown under the place name.
latitudenumberRequiredDecimal degrees.
longitudenumberRequiredDecimal degrees.
namestring | nullRequiredPlace name shown in the bubble.
participantstring | nullRequiredIn group chats, the individual sender behind `from`.
pollobjectOptionalPoll payload of a `poll` message. Votes arrive later as `polls` webhook events.
multiplebooleanRequiredWhether voters may select more than one option.
optionsarray of stringRequiredAnswer options in display order.
titlestringRequiredPoll question.
rawobjectOptionalUntouched engine payload. Present only while `settings.include_raw` is enabled.
sourcestringRequired`app` when the message came from the linked phone, `api` when Wapito sent it.one of app, api
statusstringOptionalDelivery state of an outbound message.one of failed, pending, sent, delivered, read, played
stickerobjectOptionalMedia attached to a message. `link` is a signed Wapito URL, not a WhatsApp CDN URL.
captionstring | nullRequiredCaption sent alongside the media.
errorstringOptionalSet to `unavailable` when the media could not be copied before it expired on the engine.one of unavailable
file_namestring | nullRequiredOriginal file name when the sender supplied one.
file_sizeinteger | nullRequiredSize in bytes.
idstring | nullRequiredWapito media id (`med_` + ULID), or `null` when the copy from the engine failed.
linkstring | nullRequiredSigned `/v1/media/{id}?exp&sig` URL, valid 24 h on sandbox and 7 days on premium.
mime_typestringRequiredIANA media type reported by WhatsApp.
textobjectOptionalBody of a `text` message.
bodystringRequiredMessage text, WhatsApp markdown allowed.
timestampintegerRequiredUnix epoch milliseconds.
typestringRequiredMessage kind; selects which payload field is populated.one of text, image, video, audio, voice, document, sticker, location, contact, poll, reaction, unknown
videoobjectOptionalMedia attached to a message. `link` is a signed Wapito URL, not a WhatsApp CDN URL.
captionstring | nullRequiredCaption sent alongside the media.
errorstringOptionalSet to `unavailable` when the media could not be copied before it expired on the engine.one of unavailable
file_namestring | nullRequiredOriginal file name when the sender supplied one.
file_sizeinteger | nullRequiredSize in bytes.
idstring | nullRequiredWapito media id (`med_` + ULID), or `null` when the copy from the engine failed.
linkstring | nullRequiredSigned `/v1/media/{id}?exp&sig` URL, valid 24 h on sandbox and 7 days on premium.
mime_typestringRequiredIANA media type reported by WhatsApp.
voiceobjectOptionalMedia attached to a message. `link` is a signed Wapito URL, not a WhatsApp CDN URL.
captionstring | nullRequiredCaption sent alongside the media.
errorstringOptionalSet to `unavailable` when the media could not be copied before it expired on the engine.one of unavailable
file_namestring | nullRequiredOriginal file name when the sender supplied one.
file_sizeinteger | nullRequiredSize in bytes.
idstring | nullRequiredWapito media id (`med_` + ULID), or `null` when the copy from the engine failed.
linkstring | nullRequiredSigned `/v1/media/{id}?exp&sig` URL, valid 24 h on sandbox and 7 days on premium.
mime_typestringRequiredIANA media type reported by WhatsApp.
muted_untilinteger | nullRequiredUnix epoch milliseconds the mute expires, or `null`.
namestring | nullRequiredDisplay name: contact name, group subject or channel name.
picturestring | nullRequiredURL of the chat picture, when the engine could resolve it.
pinnedbooleanRequiredWhether the chat is pinned to the top of the list.
timestampinteger | nullRequiredUnix epoch milliseconds of the most recent message.
typestringRequiredChat kind.one of individual, group, newsletter
unread_countintegerRequiredUnread messages the linked phone still shows.
{
  "archived": false,
  "id": "15551234567@s.whatsapp.net",
  "last_message": null,
  "muted_until": null,
  "name": "Dana Whitfield",
  "picture": "https://pps.whatsapp.net/v/t61.24694-24/example_n.jpg",
  "pinned": false,
  "timestamp": 1789459321000,
  "type": "individual",
  "unread_count": 1
}

400

The request body or query string is malformed, or the recipient cannot be parsed into a WhatsApp id.

Show 2 example bodies

invalid_recipient — `to` is not a dialable number or valid WhatsApp id

{
  "error": {
    "code": "invalid_recipient",
    "details": {
      "to": "+1555"
    },
    "message": "The recipient is not a valid WhatsApp address.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

invalid_request — schema validation failed

{
  "error": {
    "code": "invalid_request",
    "details": {
      "issues": [
        {
          "message": "Array must contain at least 2 element(s)",
          "path": "body.options"
        }
      ]
    },
    "message": "The request payload failed validation.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

401

The channel token is missing, malformed, revoked or belongs to a deleted channel.

Show 2 example bodies

token_revoked — the token was rotated in the dashboard

{
  "error": {
    "code": "token_revoked",
    "message": "This channel token has been revoked.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

unauthorized — no or unusable Bearer token

{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid channel token.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

403

The token is valid but the channel may not perform this action right now.

Show 2 example bodies

channel_locked — billing lapsed or the channel was locked by an operator

{
  "error": {
    "code": "channel_locked",
    "details": {
      "reason": "plan_required"
    },
    "message": "This channel is locked.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

forbidden — the channel does not own the target object

{
  "error": {
    "code": "forbidden",
    "message": "You are not allowed to perform this action.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

404

The addressed object does not exist, or the number is not on WhatsApp.

Show 3 example bodies

message_not_found — the message id is unknown to the engine

{
  "error": {
    "code": "message_not_found",
    "message": "The requested message does not exist.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

not_found — unknown id

{
  "error": {
    "code": "not_found",
    "message": "The requested resource does not exist.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

not_on_whatsapp — the number is not registered

{
  "error": {
    "code": "not_on_whatsapp",
    "message": "This number is not registered on WhatsApp.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

409

The channel is in the wrong state for this action, or the account type does not support it.

Show 3 example bodies

business_account_required — labels need WhatsApp Business

{
  "error": {
    "code": "business_account_required",
    "message": "This action requires a WhatsApp Business account.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

channel_not_connected — link the number first

{
  "error": {
    "code": "channel_not_connected",
    "details": {
      "status": "qr"
    },
    "message": "The channel is not connected.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

channel_not_in_qr_state — no QR available while the session boots

{
  "error": {
    "code": "channel_not_in_qr_state",
    "details": {
      "status": "created"
    },
    "message": "The channel is not waiting for a QR scan.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

429

A rate limit, a plan quota or one of the anti-ban guards stopped the request. Every one of these is safe to retry later; read `Retry-After` when present.

Show 5 example bodies

cold_send_limit — too many first messages to new recipients this hour

{
  "error": {
    "code": "cold_send_limit",
    "details": {
      "resets_at": "2026-09-15T09:00:00.000Z",
      "window_cap": 20
    },
    "message": "The hourly limit for messages to new recipients is reached.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

quota_exceeded — plan quota for the day or month

{
  "error": {
    "code": "quota_exceeded",
    "details": {
      "quota": "sent",
      "resets_at": "2026-09-16T00:00:00.000Z",
      "used": 150
    },
    "message": "The plan quota for this resource is exhausted.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

rate_limited — per-minute API rate limit

{
  "error": {
    "code": "rate_limited",
    "details": {
      "retry_after": 12
    },
    "message": "Too many requests.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

send_rate_limited — the send queue did not drain within 20 s

{
  "error": {
    "code": "send_rate_limited",
    "details": {
      "retry_after": 5
    },
    "message": "The send queue for this channel is saturated.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

warmup_limit — the warm-up ladder cap for today

{
  "error": {
    "code": "warmup_limit",
    "details": {
      "cap": 200,
      "day": 2
    },
    "message": "The warm-up limit for this channel is reached.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

500

Something went wrong inside Wapito. Quote `request_id` when reporting it.

Show the example body

internal_error — unexpected failure

{
  "error": {
    "code": "internal_error",
    "message": "Something went wrong on our side.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

502

The engine answered with an error Wapito could not translate into a more specific code.

Show the example body

engine_error — unexpected engine failure

{
  "error": {
    "code": "engine_error",
    "details": {
      "engine": "gows",
      "status": 500
    },
    "message": "The WhatsApp engine returned an error.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

503

The engine session is not reachable. Retry with backoff.

Show the example body

engine_unavailable — engine down or restarting

{
  "error": {
    "code": "engine_unavailable",
    "details": {
      "engine": "gows"
    },
    "message": "The WhatsApp engine is unavailable.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

504

The engine did not answer before the upstream timeout.

Show the example body

engine_timeout — no answer within the deadline

{
  "error": {
    "code": "engine_timeout",
    "details": {
      "timeout_ms": 20000
    },
    "message": "The WhatsApp engine did not respond in time.",
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

Errors

Code examples

import requests

url = "https://api.wapito.com/v1/chats/15551234567@s.whatsapp.net"

payload = { "unread": True }
headers = {
    "Authorization": "Bearer wpt_YOUR_TOKEN",
    "Content-Type": "application/json"
}

response = requests.patch(url, json=payload, headers=headers)

print(response.json())

Related

Try it on your own number

Create a channel, link a WhatsApp number by QR or pairing code, and call the API in a couple of minutes. The Sandbox plan is free and needs no card.