> ## Documentation Index
> Fetch the complete documentation index at: https://docs.uppzy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# M2M Submit Chat Feedback

> Submit quality feedback for a completed chat response.

## Overview

This endpoint submits quality feedback (`good` or `bad`) for a chat response. Use feedback to help Uppzy improve answer quality over time and to track which questions are being answered well.

Feedback can only be submitted for completed requests. The feedback rating is stored and can be viewed in the dashboard analytics.

## Authentication

Requires API key in the `X-API-Key` header:

```http theme={null}
X-API-Key: <YOUR_API_KEY>
```

## Request body

<ParamField body="session_id" type="string" required>
  The session ID from the original chat request.
</ParamField>

<ParamField body="request_id" type="string" required>
  The request ID from the chat response. Used to identify which specific Q\&A pair the feedback applies to.
</ParamField>

<ParamField body="feedback" type="string" required>
  The feedback rating. One of: `good`, `bad`.

  * `good`: The answer was helpful and accurate.
  * `bad`: The answer was incomplete, inaccurate, or irrelevant.
</ParamField>

## Request example

<CodeGroup>
  ```bash curl theme={null}
  curl --request POST \
    --url "https://api.uppzy.com/api/v1/m2m/sites/<SITE_ID>/chat/feedback" \
    --header "X-API-Key: <YOUR_API_KEY>" \
    --header "Content-Type: application/json" \
    --data '{
      "session_id": "user-123-web",
      "request_id": "req_550e8400e29b41d4a716446655440000",
      "feedback": "good"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    "https://api.uppzy.com/api/v1/m2m/sites/<SITE_ID>/chat/feedback",
    {
      method: "POST",
      headers: {
        "X-API-Key": process.env.UPPZY_API_KEY,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        session_id: "user-123-web",
        request_id: "req_550e8400e29b41d4a716446655440000",
        feedback: "good",
      }),
    }
  );

  const data = await response.json();
  console.log(`Feedback submitted at: ${data.feedback_submitted_at}`);
  ```

  ```python Python theme={null}
  import requests
  import os

  response = requests.post(
      "https://api.uppzy.com/api/v1/m2m/sites/<SITE_ID>/chat/feedback",
      headers={"X-API-Key": os.environ["UPPZY_API_KEY"]},
      json={
          "session_id": "user-123-web",
          "request_id": "req_550e8400e29b41d4a716446655440000",
          "feedback": "good",
      },
  )

  response.raise_for_status()
  data = response.json()
  print(f"Status: {data['status']}")
  ```
</CodeGroup>

## Response schema

<ResponseField name="status" type="string">
  Always `ok` on success.
</ResponseField>

<ResponseField name="request_id" type="string">
  The request ID for which feedback was submitted.
</ResponseField>

<ResponseField name="feedback" type="string">
  The feedback value submitted (`good` or `bad`).
</ResponseField>

<ResponseField name="feedback_submitted_at" type="string (ISO 8601 timestamp)">
  The timestamp when the feedback was recorded. Omitted if feedback was already submitted for this request.
</ResponseField>

## Response example

<ResponseExample>
  ```json theme={null}
  {
    "status": "ok",
    "request_id": "req_550e8400e29b41d4a716446655440000",
    "feedback": "good",
    "feedback_submitted_at": "2024-06-13T14:32:45Z"
  }
  ```
</ResponseExample>

## Error responses

### 400 Bad Request

Missing or invalid fields.

```json theme={null}
{
  "error": "feedback must be 'good' or 'bad'"
}
```

Common causes:

* Missing `session_id`, `request_id`, or `feedback`
* Invalid UUID format for IDs
* Feedback value not `good` or `bad`

### 401 Unauthorized

API key is missing, invalid, expired, or revoked.

```json theme={null}
{
  "error": "invalid_api_key"
}
```

### 403 Forbidden

The API key's plan does not include M2M API access.

```json theme={null}
{
  "error": "api_access_not_available_on_plan"
}
```

### 404 Not Found

The request does not exist or does not belong to the site.

```json theme={null}
{
  "error": "request not found"
}
```

### 409 Conflict

The request has not been completed yet (still pending or failed).

```json theme={null}
{
  "error": "feedback can only be submitted for completed responses"
}
```

### 500 Internal Server Error

An unexpected error occurred.

## Implementation tips

### When to collect feedback

Collect feedback after the user has had time to read and evaluate the answer:

1. **Chat UI pattern**: Show thumbs up/down buttons below each answer
2. **Batch pattern**: Collect feedback periodically (e.g., after 5 responses)
3. **Queue pattern**: Submit feedback asynchronously after the user rates

### Feedback collection in a chat interface

```javascript theme={null}
async function submitFeedback(siteId, sessionId, requestId, isSatisfied) {
  const feedback = isSatisfied ? "good" : "bad";

  try {
    const response = await fetch(
      `https://api.uppzy.com/api/v1/m2m/sites/${siteId}/chat/feedback`,
      {
        method: "POST",
        headers: {
          "X-API-Key": process.env.UPPZY_API_KEY,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          session_id: sessionId,
          request_id: requestId,
          feedback,
        }),
      }
    );

    if (!response.ok) {
      console.error(`Feedback submission failed: ${response.status}`);
      return;
    }

    const data = await response.json();
    console.log(
      `Feedback recorded at ${data.feedback_submitted_at}`
    );
  } catch (err) {
    console.error(`Error submitting feedback: ${err}`);
  }
}

// Usage: when user clicks thumbs up
submitFeedback(siteId, sessionId, requestId, true);

// Usage: when user clicks thumbs down
submitFeedback(siteId, sessionId, requestId, false);
```

### Idempotency

Submitting the same feedback twice returns the original submission time:

```javascript theme={null}
// First submission
await submitFeedback(siteId, sessionId, requestId, "good");
// Returns: { status: "ok", feedback_submitted_at: "2024-06-13T14:32:45Z" }

// Second submission of the same feedback
await submitFeedback(siteId, sessionId, requestId, "good");
// Returns: { status: "ok", feedback_submitted_at: "2024-06-13T14:32:45Z" }
// (same timestamp as first)
```

However, changing feedback from `good` to `bad` (or vice versa) updates it:

```javascript theme={null}
// First: submit "good"
await submitFeedback(siteId, sessionId, requestId, "good");
// feedback_submitted_at: "2024-06-13T14:32:45Z"

// Later: change to "bad"
await submitFeedback(siteId, sessionId, requestId, "bad");
// feedback_submitted_at: "2024-06-13T14:35:12Z" (updated)
```

### Tracking feedback for analytics

Store feedback in your application to track quality trends:

```sql theme={null}
-- Track feedback by day
SELECT
  DATE(submitted_at) as date,
  COUNT(*) as total_responses,
  SUM(CASE WHEN feedback = 'good' THEN 1 ELSE 0 END) as good_count,
  ROUND(
    100.0 * SUM(CASE WHEN feedback = 'good' THEN 1 ELSE 0 END) / COUNT(*),
    2
  ) as satisfaction_rate
FROM feedback_logs
GROUP BY DATE(submitted_at)
ORDER BY date DESC;
```

### Error handling and retries

Feedback submission is non-critical; if it fails, log it but don't block the user:

```javascript theme={null}
async function submitFeedbackSafely(siteId, sessionId, requestId, feedback) {
  try {
    const response = await fetch(
      `https://api.uppzy.com/api/v1/m2m/sites/${siteId}/chat/feedback`,
      {
        method: "POST",
        headers: {
          "X-API-Key": process.env.UPPZY_API_KEY,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          session_id: sessionId,
          request_id: requestId,
          feedback,
        }),
        timeout: 5000, // Short timeout
      }
    );

    if (!response.ok) {
      // Log but don't throw
      console.warn(
        `Feedback submission failed (${response.status}), continuing...`
      );
    }
  } catch (err) {
    // Network or timeout error, log and continue
    console.warn(`Feedback submission error (${err.message}), continuing...`);
  }
}
```

## Dashboard integration

Feedback is visible in the Uppzy dashboard:

* Go to **Analytics** → **Feedback** to see satisfaction rates over time
* Filter by date range, question topic, or confidence level
* Use low-satisfaction answers to prioritize document improvements

## Related endpoints

* [M2M Chat (Sync)](/api-reference/endpoint/m2m-chat-sync) — Send a message
* [M2M Chat (Async)](/api-reference/endpoint/m2m-chat-async) — Non-blocking messages
* [M2M Session List](/api-reference/endpoint/m2m-sessions) — List conversations
* [M2M Site Statistics](/api-reference/endpoint/m2m-site-statistics) — Feedback trends
