> ## 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 Close Chat Session

> Mark a chat session as closed.

## Overview

This endpoint marks a chat session as closed. Closed sessions are archived and no longer receive new messages.

Use this when:

* A user ends a conversation
* A support ticket is resolved
* A session is inactive for an extended period
* You want to create a new session for the same user (fresh context)

Closing a session is idempotent: closing an already-closed session returns success.

## 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 to close.
</ParamField>

## Request example

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

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

  const data = await response.json();
  console.log(data.status); // "ok"
  ```

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

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

  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>

## Response example

<ResponseExample>
  ```json theme={null}
  {
    "status": "ok"
  }
  ```
</ResponseExample>

## Error responses

### 400 Bad Request

Missing or invalid session ID.

```json theme={null}
{
  "error": "session_id is required"
}
```

### 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 site does not exist.

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

### 500 Internal Server Error

An unexpected error occurred.

## Implementation tips

### Idempotency

Closing an already-closed session returns success:

```javascript theme={null}
// First close
await fetch(...POST /chat/session/close...);
// Returns: { status: "ok" }

// Second close (same session)
await fetch(...POST /chat/session/close...);
// Returns: { status: "ok" } (no error)
```

### When to close a session

Close sessions in these scenarios:

1. **User-initiated**: User clicks "End conversation" or closes the chat widget
2. **Time-based**: Close sessions inactive for > 24 hours
3. **Status-based**: Close sessions when a support ticket is resolved
4. **Context shift**: Start a new session when switching topics

```javascript theme={null}
// Example: close after 24 hours of inactivity
async function closeInactiveSessions(siteId, olderThanHours = 24) {
  // Get all sessions
  const sessionsResp = await fetch(
    `https://api.uppzy.com/api/v1/m2m/sites/${siteId}/sessions`,
    {
      headers: { "X-API-Key": process.env.UPPZY_API_KEY },
    }
  );
  const { sessions } = await sessionsResp.json();

  // Filter inactive sessions
  const now = new Date();
  const inactiveSessions = sessions.filter((session) => {
    if (session.closed_at) return false; // Already closed
    const lastActivity = new Date(session.updated_at);
    const hoursSinceActivity = (now - lastActivity) / (1000 * 60 * 60);
    return hoursSinceActivity > olderThanHours;
  });

  // Close them
  for (const session of inactiveSessions) {
    await fetch(
      `https://api.uppzy.com/api/v1/m2m/sites/${siteId}/chat/session/close`,
      {
        method: "POST",
        headers: {
          "X-API-Key": process.env.UPPZY_API_KEY,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ session_id: session.id }),
      }
    );
  }

  console.log(`Closed ${inactiveSessions.length} inactive sessions`);
}
```

### Starting a fresh session after closing

When you close a session and want the user to continue, use a new session ID:

```javascript theme={null}
async function restartConversationWithFreshSession(
  siteId,
  oldSessionId,
  userEmail
) {
  // Close the old session
  await fetch(
    `https://api.uppzy.com/api/v1/m2m/sites/${siteId}/chat/session/close`,
    {
      method: "POST",
      headers: {
        "X-API-Key": process.env.UPPZY_API_KEY,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ session_id: oldSessionId }),
    }
  );

  // Start fresh with a new session ID
  const newSessionId = `${userEmail}-${Date.now()}`;
  const response = await fetch(
    `https://api.uppzy.com/api/v1/m2m/sites/${siteId}/chat`,
    {
      method: "POST",
      headers: {
        "X-API-Key": process.env.UPPZY_API_KEY,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        session_id: newSessionId,
        message: "Hi, I'm starting a new conversation.",
        email: userEmail,
      }),
    }
  );

  return response.json();
}
```

### Batch closing multiple sessions

Close multiple sessions efficiently:

```javascript theme={null}
async function closeMultipleSessions(siteId, sessionIds) {
  const promises = sessionIds.map((sessionId) =>
    fetch(
      `https://api.uppzy.com/api/v1/m2m/sites/${siteId}/chat/session/close`,
      {
        method: "POST",
        headers: {
          "X-API-Key": process.env.UPPZY_API_KEY,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ session_id: sessionId }),
      }
    )
  );

  const results = await Promise.all(promises);
  const successCount = results.filter((r) => r.ok).length;

  console.log(`Successfully closed ${successCount}/${sessionIds.length} sessions`);
}
```

### Marking session state in your database

Track which sessions you've closed:

```javascript theme={null}
async function closeSessionAndLog(siteId, sessionId, userId) {
  // Close on Uppzy
  const response = await fetch(
    `https://api.uppzy.com/api/v1/m2m/sites/${siteId}/chat/session/close`,
    {
      method: "POST",
      headers: {
        "X-API-Key": process.env.UPPZY_API_KEY,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ session_id: sessionId }),
    }
  );

  if (response.ok) {
    // Update your database
    await db.query(
      `UPDATE chat_sessions SET closed_at = NOW() WHERE session_id = ?`,
      [sessionId]
    );
  }
}
```

## 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 message
* [M2M Session List](/api-reference/endpoint/m2m-sessions) — List all sessions
* [M2M Chat Feedback](/api-reference/endpoint/m2m-chat-feedback) — Rate a response
