# Set a message's status

```http
PUT https://secure.yoprint.com/v2/api/store/{team_slug}/messages/{hash_id}/status
```

- API version: v2
- Operation ID: `v2_public_messages_status`
- Section: Messages and activity › [Messages](https://developer.yoprint.com/reference/messages.md)
- Web page: https://developer.yoprint.com/reference/messages/v2-messages-status/
- Authentication: `Authorization: Bearer YOUR_API_KEY`

Sets your team's own status on a message, such as "Need to Respond" or "Completed", for sorting your inbox. It does not change delivery and does not notify the customer.

Use a status id from your team's message statuses (`GET /v1/api/store/{team_slug}/setting/status/customer_message`). Returns the message with `previous_status_id` and `previous_message_status`.

## Permission

Any member can read purchase order messages. For sales order and quote messages you need permission to message all orders, or only the orders you created or are assigned to. The team owner sees everything.

## Business rules

- `status_id` is required and must be one of your team's statuses. Use a message status: other kinds of status are accepted too, but they are not meant for messages.

## Side effects

- Fires the `message.status_changed` webhook, every time, even if the status was already set to this value.
- Records the change in the status history when the message had a different status before.
- People with the inbox open see the change live.

## Path parameters

- `team_slug` (string, required): Your team slug, shown as Team ID next to your API key in Profile. Example `your-team`.
- `hash_id` (string, required): The message's `id`, from the message list. A hash id; unique keys and document numbers are refused with 404. Example `u7HKhdhT6tkEUy`.

## Request body

Content type `application/json`, required.

Fields:

- `status_id` (string, required): One of your team's message status ids.
- `notify_customer` (boolean, optional): Accepted but ignored: no notification is sent.

### Example request

```bash
curl -X PUT 'https://secure.yoprint.com/v2/api/store/your-team/messages/u7HKhdhT6tkEUy/status' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Accept: application/json' \
  -H 'X-Yoprint-Decimal-Format: exact-v1' \
  -H 'Content-Type: application/json' \
  -d '{
    "status_id": "aEVC1y7DeLogrF"
  }'
```

## Response

`200` Successful response.

Fields:

- `data` (object, required)
  - `actor_name` (string | null, optional): The writer's name, by `actor_type`: your team's name for `system`, the team member, the contact, the order's customer, the purchase order's vendor, the participant, or the name a `guest` gave. Null when YoPrint can't find the writer's record.
  - `actor_type` (string, optional): Who wrote it: `user`, `customer`, `vendor`, `contact` (written in the customer or vendor portal), `participant`, `guest` (someone who is not a contact) or `system`.
  - `attachments` (array of objects, optional): Files attached to it, in the same shape as an upload (`id`, `name`, `file_name`, `mime_type`, `size`, `url`).
  - `contact` (object | null, optional): The contact who wrote it, when `contact_id` is set: `first_name`, `last_name`, `email`, `phone` and more.
  - `contact_id` (string | null, optional)
  - `created_at` (string (date-time), optional)
  - `delivery_summary` (object | null, optional): Outbound messages: how delivery went across all recipients. Null for inbound messages.
    - `accepted` (integer, optional)
    - `complete` (boolean, optional)
    - `delivered` (integer, optional)
    - `failed` (integer, optional)
    - `reason` (string | null, optional): Why the state is not final, or why nothing was sent, for example `no_recipients` or `delivery_evidence_unavailable`. Usually null.
    - `retryable` (boolean, optional): True when the retry operation accepts this message. When false, it answers 422.
    - `skipped` (integer, optional)
    - `state` (string, optional): `sent`: the provider took it, delivery not confirmed yet. `partial`: recipients are in different states. `not_sent`: there were no recipients. One of: `"pending"`, `"sending"`, `"sent"`, `"delivered"`, `"failed"`, `"partial"`, `"unknown"`, `"not_sent"`.
    - `submitting` (integer, optional)
    - `total` (integer, optional)
    - `unknown` (integer, optional)
    - `waiting` (integer, optional)
  - `display_type` (string, optional): How the web app draws it, for example `default_v2`, or `system_v2` for automatic messages.
  - `driver` (string | null, optional): `email`, `sms`, or `web` for a message written in YoPrint.
  - `email` (string | null, optional): The sender's email address.
  - `has_message` (boolean, optional)
  - `has_original_message` (boolean, optional)
  - `id` (string, optional)
  - `message` (string | null, optional): The message as it was written, without the email layout.
  - `message_participant_id` (string | null, optional): The author, as a message participant.
  - `message_status` (object | null, optional): The status named by `status_id`: `id`, `role` (`customer_message`), `type`, `label`, `customer_label`, `color`, `position`, `trashed`.
  - `name` (string | null, optional): The sender's name.
  - `order_id` (string | null, optional): The sales order or quote it is on.
  - `order_object_type` (string | null, optional): `sales_order` or `quote`. Null without an order.
  - `order_quote` (boolean | null, optional)
  - `order_scoped_id` (string | null, optional): The order's number, such as `SO1001`. An empty string `""` (not null) without an order.
  - `original_message` (string | null, optional): The whole message as HTML: for a reply, the email as it arrived, with any quoted text; for a message you sent, the full message YoPrint rendered.
  - `participant` (object | null, optional): The author, as a message participant, when `message_participant_id` is set. Its `delivery_*` fields are null.
    - `can_receive_mail` (boolean, optional)
    - `can_receive_sms` (boolean, optional)
    - `contact` (object | null, optional): The contact, for `type` `contact`: `first_name`, `last_name`, `email`, `phone` and more.
    - `contact_id` (string | null, optional)
    - `delivery_channel` (string | null, optional): One of: `"email"`, `"sms"`.
    - `delivery_created_at` (string (date-time) | null, optional)
    - `delivery_destination` (string | null, optional): The email address or phone number it went to.
    - `delivery_destination_name` (string | null, optional)
    - `delivery_id` (string | null, optional): The recipient id: the id the recipient operations take. Null on `participant`.
    - `delivery_latest_error_reason` (string | null, optional)
    - `delivery_message_id` (string | null, optional)
    - `delivery_participant_id` (string | null, optional)
    - `delivery_state` (string | null, optional): From the provider's report. Null for older messages and on `participant`. One of: `"pending"`, `"sending"`, `"sent"`, `"delivered"`, `"failed"`, `"unknown"`.
    - `delivery_status` (string | null, optional): One of: `"pending"`, `"dispatched"`, `"dispatch_failed"`, `"delivered"`, `"delivery_failed"`.
    - `delivery_updated_at` (string (date-time) | null, optional)
    - `email` (string | null, optional)
    - `id` (string, optional): The participant id. The recipient operations take `delivery_id`, not this.
    - `name` (string | null, optional)
    - `order_id` (string | null, optional)
    - `phone` (string | null, optional)
    - `purchase_order_id` (string | null, optional)
    - `status` (string, optional): What they receive: `message`, `notification`, `all` or `disabled`.
    - `trashed` (boolean, optional)
    - `type` (string, optional): `user`: a team member. `contact`: one of the customer's or vendor's contacts. `guest`: just a name and email. One of: `"user"`, `"contact"`, `"guest"`.
  - `preview_message` (string | null, optional): A short plain-text preview.
  - `previous_message_status` (object | null, optional): That status, in the same shape as `message_status`: `id`, `role`, `type`, `label`, `customer_label`, `color`, `position`, `trashed`.
  - `previous_status_id` (string | null, optional): The status before this change. Null when none was set.
  - `purchase_order_id` (string | null, optional): The purchase order it is on.
  - `purchase_scoped_id` (string | null, optional): The purchase order's number. Null when it is not on a purchase order.
  - `recipients` (array of objects, optional): Who it was sent to: each participant with its delivery (`delivery_status`, `delivery_channel`, `delivery_destination`). `delivery_id` is the id the recipient operations take.
    - Each item:
      - `can_receive_mail` (boolean, optional)
      - `can_receive_sms` (boolean, optional)
      - `contact` (object | null, optional): The contact, for `type` `contact`: `first_name`, `last_name`, `email`, `phone` and more.
      - `contact_id` (string | null, optional)
      - `delivery_channel` (string | null, optional): One of: `"email"`, `"sms"`.
      - `delivery_created_at` (string (date-time) | null, optional)
      - `delivery_destination` (string | null, optional): The email address or phone number it went to.
      - `delivery_destination_name` (string | null, optional)
      - `delivery_id` (string | null, optional): The recipient id: the id the recipient operations take. Null on `participant`.
      - `delivery_latest_error_reason` (string | null, optional)
      - `delivery_message_id` (string | null, optional)
      - `delivery_participant_id` (string | null, optional)
      - `delivery_state` (string | null, optional): From the provider's report. Null for older messages and on `participant`. One of: `"pending"`, `"sending"`, `"sent"`, `"delivered"`, `"failed"`, `"unknown"`.
      - `delivery_status` (string | null, optional): One of: `"pending"`, `"dispatched"`, `"dispatch_failed"`, `"delivered"`, `"delivery_failed"`.
      - `delivery_updated_at` (string (date-time) | null, optional)
      - `email` (string | null, optional)
      - `id` (string, optional): The participant id. The recipient operations take `delivery_id`, not this.
      - `name` (string | null, optional)
      - `order_id` (string | null, optional)
      - `phone` (string | null, optional)
      - `purchase_order_id` (string | null, optional)
      - `status` (string, optional): What they receive: `message`, `notification`, `all` or `disabled`.
      - `trashed` (boolean, optional)
      - `type` (string, optional): `user`: a team member. `contact`: one of the customer's or vendor's contacts. `guest`: just a name and email. One of: `"user"`, `"contact"`, `"guest"`.
  - `rendered_attachments` (array of objects, optional): Everything attached when it was sent: the files (`attachment_type` `media`, upload shape) and generated documents such as the order PDF (`attachment_type` `internal_attachment`, with `name` and `url`).
  - `retryable` (boolean, optional): For outbound messages, the same as `delivery_summary.retryable`.
  - `status` (string | null, optional): Older delivery status word, such as `pending`, `dispatched`, `partial_delivered`, `delivery_failed`, `delivered`, or `received` for a reply. Prefer `delivery_summary`.
  - `status_id` (string | null, optional): Your team's message status (for example "Needs reply"), set with the status operation. Null when none is set.
  - `system` (boolean, optional): True for messages YoPrint sent automatically.
  - `type` (string, optional): `outbound`: sent by your team. `inbound`: a reply received. One of: `"outbound"`, `"inbound"`.
  - `user` (object | null, optional): The team member who wrote it, when `user_id` is set.
    - `avatar_url` (string | null, optional)
    - `email` (string, optional)
    - `id` (string, optional)
    - `name` (string, optional)
    - `timezone` (string | null, optional)
  - `user_id` (string | null, optional)
- `status` (integer, required)
- `success` (boolean, required)

Example response:

```json
{
  "data": {
    "actor_name": "Alex Rivera",
    "actor_type": "user",
    "attachments": [],
    "contact": null,
    "contact_id": null,
    "created_at": "2026-11-03T09:30:00+00:00",
    "delivery_summary": {
      "accepted": 0,
      "complete": true,
      "delivered": 0,
      "failed": 1,
      "reason": null,
      "retryable": true,
      "skipped": 0,
      "state": "failed",
      "submitting": 0,
      "total": 1,
      "unknown": 0,
      "waiting": 0
    },
    "display_type": "default_v2",
    "driver": "email",
    "email": "alex@example.com",
    "has_message": true,
    "has_original_message": true,
    "id": "u7HKhdhT6tkEUy",
    "message": "<p>Your order is ready for pickup.</p>",
    "message_participant_id": null,
    "message_status": {
      "color": "#c6ff00",
      "customer_label": "In Progress",
      "id": "aEVC1y7DeLogrF",
      "label": "Need to Respond",
      "position": 1,
      "role": "customer_message",
      "trashed": false,
      "type": "in_progress"
    },
    "name": "Alex Rivera",
    "order_id": "V4keXwwxMQyXw7",
    "order_object_type": "sales_order",
    "order_quote": false,
    "order_scoped_id": "SO1001",
    "original_message": "<html><body><p>Your order is ready for pickup.</p></body></html>",
    "participant": null,
    "preview_message": "Your order is ready for pickup.",
    "previous_message_status": null,
    "previous_status_id": null,
    "purchase_order_id": null,
    "purchase_scoped_id": null,
    "recipients": [
      {
        "can_receive_mail": true,
        "can_receive_sms": false,
        "contact": {
          "created_at": "2026-11-01T09:00:00+00:00",
          "customer_id": "63KcENAAsKuipY",
          "default_receive_sms": false,
          "email": "jordan@example.com",
          "external_type": null,
          "fax": null,
          "fax_country": null,
          "first_name": "Jordan",
          "id": "uTCR3hxPDePBUK",
          "is_external": false,
          "is_primary": true,
          "last_name": "Lee",
          "phone": "+1 201 555 0123",
          "phone_country": "US",
          "send_invoice": true,
          "trashed": false,
          "updated_at": "2026-11-01T09:00:00+00:00"
        },
        "contact_id": "uTCR3hxPDePBUK",
        "delivery_channel": "email",
        "delivery_created_at": "2026-11-03T09:30:00+00:00",
        "delivery_destination": "jordan@example.com",
        "delivery_destination_name": "Jordan Lee",
        "delivery_id": "XWwTVKIZSuUOcX",
        "delivery_latest_error_reason": "The server was unable to deliver your message (ex: unknown user, mailbox not found).",
        "delivery_message_id": "u7HKhdhT6tkEUy",
        "delivery_participant_id": "vKNPqQz8fsYDuT",
        "delivery_state": "failed",
        "delivery_status": "delivery_failed",
        "delivery_updated_at": "2026-11-03T09:31:00+00:00",
        "email": "jordan@example.com",
        "id": "vKNPqQz8fsYDuT",
        "name": "Jordan Lee",
        "order_id": "V4keXwwxMQyXw7",
        "phone": "+1 201 555 0123",
        "purchase_order_id": null,
        "status": "all",
        "trashed": false,
        "type": "contact"
      }
    ],
    "rendered_attachments": [],
    "retryable": true,
    "status": "delivery_failed",
    "status_id": "aEVC1y7DeLogrF",
    "system": false,
    "type": "outbound",
    "user": {
      "avatar_url": "https://example.com/avatar.png",
      "email": "alex@example.com",
      "id": "VG7s3tFzyQbO2N",
      "name": "Alex Rivera",
      "timezone": "America/New_York"
    },
    "user_id": "VG7s3tFzyQbO2N"
  },
  "status": 200,
  "success": true
}
```

## Errors

- `401` The API key is missing or wrong (`unauthenticated`).
- `403` You are not allowed to do this. `api_access_not_in_plan`: your team's plan doesn't include API access (Pro and above, with an active subscription or trial), so every request answers this until the team upgrades. When your role lacks the permission the operation needs, the body is only `{"message": "Insufficient Permission"}`. Other refusals use the error envelope, with `unauthorized` or `user_is_not_authorized`.
  - When: The message is on a sales order or quote you can't message (`user_is_not_authorized`). Fix: Ask a team admin for permission to message that order.
- `404` Not found. `page_not_found`: the team slug is unknown, you are not a member of the team, or an id in the path is not one of this team's. `code: null`, with a message that starts "No query results for": there is no record with that id.
  - When: The message or the status does not exist on this team. Fix: Use ids from the API.
- `422` The request was refused and changed nothing. `validation_failed` lists what to fix in `error.fields`; other codes name a business rule, explained in `error.message`. A few checks answer with only `{"message": "..."}`. An operation that calls another service (a payment provider, a carrier, an accounting app) can answer `connect_timeout` ("Please retry again") when that service does not answer in time: the change may or may not have happened there, so read the record back before you retry.
  - When: `status_id` is missing or not an id, or `notify_customer` is not a boolean (`validation_failed`; `error.fields` names the field). Fix: Send a status id.

## Related

- [List message thread statuses](https://developer.yoprint.com/reference/statuses/v1-status-list-customer-message.md): `GET /v1/api/store/{team_slug}/setting/status/customer_message`
- [Filter messages](https://developer.yoprint.com/reference/messages/v2-messages-filter.md): `POST /v2/api/store/{team_slug}/messages/filter`
