---
title: "Cancel an in-flight agent chat stream"
method: POST
path: "/agents/{agentKey}/conversations/{conversationId}/cancel"
tags: ["Agents"]
---

# Cancel an in-flight agent chat stream

`POST /agents/{agentKey}/conversations/{conversationId}/cancel`

## Request

- Base URL: `https://app.pipeshub.com/api/v1`
- URL: `https://app.pipeshub.com/api/v1/agents/{agentKey}/conversations/{conversationId}/cancel`
- Auth: one of:
  - HTTP bearer
  - OAuth 2
    - Authorization code: `/api/v1/oauth2/authorize`
    - Client credentials
    - Token URL: `/api/v1/oauth2/token` scopes: `agent:execute`

Cooperatively stop a `POST /agents/{agentKey}/conversations/stream`
or `.../messages/stream` run that is still generating, using the
`runId` sent when that stream started.

Same synchronous JSON ack contract as the assistant
`POST /conversations/{conversationId}/cancel` — both forward to the
same backend cancellation endpoint, since the run registry is keyed
by `runId` alone.

`cancelled` reports whether a stop request was issued, not whether a
run was actually stopped. With the default shared (key-value backed)
run registry, a `runId` that the answering worker does not hold is
published for whichever worker owns it, and the answer is
`{ cancelled: true }` even when the run already finished or was
never registered. `{ cancelled: false }` is returned for such a
`runId` only when the registry is in-process, or when the stop
request could not be published.

`runId` must belong to a run started on THIS `conversationId` — a
`runId` that exists but was registered under a different
conversation (even one owned by the same caller) is rejected with
`403`, same as a `runId` owned by a different user/org.

## Path parameters

- `agentKey` string, required
- `conversationId` string, objectId, required

## Request body

- object
  - `runId` string, uuid, required: The `runId` sent when the stream was started. Anything but a UUID string is refused with `VALIDATION_ERROR`.

## Response `200`

Cancellation requested, or the run had already finished.

- object
  - `cancelled` boolean, required: `true` when a stop request was issued for `runId`; `false` when the run is unknown to an in-process registry or the request could not be published.

## Other responses

- `400`: Missing or malformed `runId`.
- `401`: Unauthorized
- `403`: The access token lacks the `agent:execute` OAuth scope, or `runId` belongs to a run still in flight that was registered under a different user, org, or conversation than this request. Once that run has ended its `runId` is unknown and the answer is 200.
- `404`: Conversation not found or unauthorized
- `500`: Internal server error. A JSON body larger than 10 MB, or a form-encoded body larger than 100 KB or with more than 1000 fields, is answered `413` by the app-wide body parsers instead, also before authentication.

## Changes

- **2026-10-28** `dbb5e203b445`: 1 breaking, 7 info
  - added the pattern `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$` to the request property `runId`
  - added the media type `application/x-www-form-urlencoded` to the request body
  - added the media type `application/json` for the response with the status `400`
  - added the media type `application/json` for the response with the status `401`
  - …4 more
- **2026-10-08** `bb0c59adf026`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/pipeshub-ai/apis/pipeshub-api/changes/agents/:agentKey/conversations/:conversationId/cancel/post.md)

---

[API](https://skmtc.dev/pipeshub-ai/apis/pipeshub-api.md) - [All operations](https://skmtc.dev/pipeshub-ai/apis/pipeshub-api/llms.txt) - [OpenAPI document](https://skmtc.dev/pipeshub-ai/apis/pipeshub-api/revisions/dbb5e203b445?raw)
