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

> ## Agent Instructions
> Use Stable documentation by default. Honor an explicit Beta request or a URL under /docs/beta/. If the requested version conflicts with the installed CLI package or API origin, clarify the target before writing integration code.
> Pages under /docs/beta/ document Beta; other product pages document Stable. Keep the CLI package, commands, API origin, and credentials within the selected version. State the documentation version in your answer.
> For MCP search, always pass version: Stable or version: Beta. Unfiltered search mixes both versions. For filesystem reads, keep Beta queries under /beta/ and exclude /beta/ from Stable queries; discover paths before reading them.
> The public docs base is https://photon.codes/docs. Convert MCP page paths to public URLs under that base, preserving /beta/ when present. Read https://photon.codes/docs/skill.md for version selection and https://photon.codes/docs/llms.txt for the version indexes.

# Cancel operation

> Cancel operation: cancelOperation in the TypeScript, Python and Rust clients.

`POST /v1/projects/{id}/platforms/operations/{operationId}/cancel`

Withdraws a provision that has not been fulfilled yet. This is an operations action rather than a DELETE, because there is nothing to delete: no resource exists until the work commits. Whether it is accepted depends on the resource type — a dedicated iMessage line may sit waiting on inventory for hours and withdrawing costs nothing, while an SMS number is cancellable during inventory waiting and answers 409 once the workflow commits to its first provider order. Campaign assignment and detachment operations cannot be cancelled in any state. Wait for completion before requesting another change; that new change is not a guaranteed rollback. The output-only `cancellable` field is a snapshot; the cancellation transaction always checks the current phase under a row lock. A cancel that loses the race against the work finishing also answers 409: the resource exists and is billed for, so what you want then is to release it. Nothing is charged for a cancelled provision — billing runs after the work, so there is never anything to refund. Requires the platforms:write permission bound to the project resource in the path.

<Tabs>
  <Tab title="TypeScript">
    ```typescript TypeScript theme={null}
    photon.projects.platforms.cancelOperation(input: CancelOperationInput, options?: RequestOptions): Promise<CancelOperationOutput>
    ```
  </Tab>

  <Tab title="Python">
    ```python Python theme={null}
    photon.projects.platforms.cancel_operation(input: CancelOperationInput) -> models.Operation
    ```
  </Tab>

  <Tab title="Rust">
    ```rust Rust theme={null}
    client.cancel_operation(id: String, operation_id: String).await -> Result<ResponseValue<types::Operation>, Error<CancelOperationError>>
    ```
  </Tab>
</Tabs>

<RequestExample>
  ```typescript TypeScript theme={null}
  import { Photon } from "@photon-ai/api";

  const photon = new Photon({
    headers: { Authorization: `Bearer ${process.env.PHOTON_API_TOKEN}` },
  });
  const result = await photon.projects.platforms.cancelOperation({
    path: {
      id: "id",
      operationId: "operationId",
    },
  });
  ```

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

  from photon_api import Photon
  from photon_api.rpc_generated import CancelOperationInput

  photon = Photon(headers={"Authorization": f"Bearer {os.environ['PHOTON_API_TOKEN']}"})
  result = photon.projects.platforms.cancel_operation(
      CancelOperationInput.model_validate({
          "path": {
              "id": "id",
              "operationId": "operationId",
          },
      })
  )
  ```

  ```rust Rust theme={null}
  use photon_ai_api::{Credential, PhotonClientBuilder, SecretString};

  let token = std::env::var("PHOTON_API_TOKEN")?;
  let client = PhotonClientBuilder::new()
      .credential("accountServiceKey", Credential::Bearer(SecretString::from(token)))
      .build()?;
  let result = client
      .cancel_operation("id".to_owned(), "operationId".to_owned())
      .await
      .map_err(|error| format!("{error:?}"))?
      .into_inner();
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "cancellable": true,
    "createdAt": "2026-01-01T00:00:00.000Z",
    "detail": {},
    "endedAt": "2026-01-01T00:00:00.000Z",
    "error": {
      "code": "string",
      "detail": "string"
    },
    "operationId": "string",
    "projectId": "string",
    "reason": "charge_refused",
    "resourceId": "string",
    "resourceType": "string",
    "startedAt": "2026-01-01T00:00:00.000Z",
    "state": "pending",
    "type": "resource.provision",
    "updatedAt": "2026-01-01T00:00:00.000Z"
  }
  ```
</ResponseExample>

## Parameters

<ParamField path="id" type={"string"} required />

<ParamField path="operationId" type={"string"} required />

## Returns

**`200`** The cancelled operation. Operation

<ResponseField name="cancellable" type={"boolean"} required />

<ResponseField name="createdAt" type={"string (date-time)"} required />

<ResponseField name="detail" type={"object"} />

<ResponseField name="endedAt" type={"string (date-time)"} />

<ResponseField name="error" type={"OperationError"} />

<ResponseField name="operationId" type={"string"} required />

<ResponseField name="projectId" type={"string"} required />

<ResponseField name="reason" type={"OperationReason"} />

<ResponseField name="resourceId" type={"string"} />

<ResponseField name="resourceType" type={"string"} required />

<ResponseField name="startedAt" type={"string (date-time)"} />

<ResponseField name="state" type={"OperationState"} required />

<ResponseField name="type" type={"OperationType"} required />

<ResponseField name="updatedAt" type={"string (date-time)"} required />


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.