<!--
{
  "availability" : [
    "iOS: 26.4.0 -",
    "iPadOS: 26.4.0 -",
    "macCatalyst: -",
    "macOS: 26.4.0 -",
    "tvOS: 26.4.0 -",
    "visionOS: 26.4.0 -",
    "watchOS: 26.4.0 -"
  ],
  "documentType" : "symbol",
  "framework" : "AppIntents",
  "identifier" : "/documentation/AppIntents/CancellableIntent",
  "metadataVersion" : "0.1.0",
  "role" : "Protocol",
  "symbol" : {
    "kind" : "Protocol",
    "modules" : [
      "App Intents"
    ],
    "preciseIdentifier" : "s:10AppIntents17CancellableIntentP"
  },
  "title" : "CancellableIntent"
}
-->

# CancellableIntent

An interface to support the graceful cancellation of your app intent’s task.

```
protocol CancellableIntent : AppIntent
```

## Overview

This protocol adds cancellation support to your app intent types. Use it to let the
system know that you need additional time to perform cleanup operations when your app
intent receives a cancellation notification. To use this protocol, use the
[`withIntentCancellationHandler(operation:onCancel:isolation:)`](/documentation/AppIntents/CancellableIntent/withIntentCancellationHandler(operation:onCancel:isolation:)) method
to wrap your app intent’s task. With this method in place, the system gives your
code extra time to handle cancellation before the app intent’s task ends.

The system can cancel an app intent for the following reasons:

- The app intent didn’t report progress and exceeded its 30-second runtime limit.
- Someone monitoring the progress of the app intent in Siri, Live Activities, or Shortcuts
  chose to cancel the task.

Swift provides the standard <doc://com.apple.documentation/documentation/Swift/withTaskCancellationHandler(handler:operation:)>
function for tasks to handle cancellation. You can use that function in your app intent’s
[`perform()`](/documentation/AppIntents/AppIntent/perform()) method to perform any cleanup tasks if you don’t need to know the
reason cancellation occurred. If you want to know the reason for cancellation, use the
[`withIntentCancellationHandler(operation:onCancel:isolation:)`](/documentation/AppIntents/CancellableIntent/withIntentCancellationHandler(operation:onCancel:isolation:)) method
that this protocol offers instead. When cancellation occurs, stop your app intent’s current task,
release any allocated memory or resources, save intermediate state as needed, and write
out any relevant diagnostic information related to the cancellation.

The following example shows a payment-processing app intent and the basic code it uses to
perform its task. The app intent’s [`perform()`](/documentation/AppIntents/AppIntent/perform()) method calls the
[`withIntentCancellationHandler(operation:onCancel:isolation:)`](/documentation/AppIntents/CancellableIntent/withIntentCancellationHandler(operation:onCancel:isolation:)) method to
process the payment and handle cancellation if it occurs. The cancellation handler performs
different tasks based on whether the someone canceled the operation deliberately or the
system timed out.

```swift
enum PaymentMethod: String, AppEnum {
    case creditCard
    case debitCard

    static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Payment Method")
    static var caseDisplayRepresentations: [PaymentMethod: DisplayRepresentation] = [
        .creditCard: "Credit Card",
        .debitCard: "Debit Card"
    ]
}

class PaymentService {
    func initiateTransaction(_ id: UUID, amount: Decimal) async throws {
        // Initiate payment transaction
    }

    func authorize(_ id: UUID, method: PaymentMethod) async throws {
        // Authorize payment
    }

    func process(_ id: UUID) async throws {
        // Process payment
    }

    func rollback(_ id: UUID, reason: String) async throws {
        // Roll back transaction
    }

    func cancel(_ id: UUID, reason: String) async throws {
        // Cancel transaction
    }
}

struct ProcessPaymentIntent: AppIntent, ProgressReportingIntent, CancellableIntent {
    static var title: LocalizedStringResource = "Process Payment"

    @Parameter var amount: Decimal
    @Parameter var paymentMethod: PaymentMethod

    private let paymentService = PaymentService()

    func perform() async throws -> some IntentResult & ProvidesDialog {
        let transactionID = UUID()

        return try await withIntentCancellationHandler {
            updateProgress(fractionCompleted: 0.0, message: "Initiating payment...")
            try await paymentService.initiateTransaction(transactionID, amount: amount)

            updateProgress(fractionCompleted: 0.3, message: "Authorizing payment...")
            try await paymentService.authorize(transactionID, method: paymentMethod)

            updateProgress(fractionCompleted: 0.7, message: "Processing payment...")
            try await paymentService.process(transactionID)

            updateProgress(fractionCompleted: 1.0, message: "Payment complete")
            return .result(dialog: "Payment of \(amount) processed successfully")
        } onCancel: { reason in
            Task {
                switch reason {
                case .timeout:
                    try? await paymentService.rollback(transactionID, reason: "timeout")
                case .userCancelled:
                    try? await paymentService.cancel(transactionID, reason: "user_cancelled")
                default:
                    try? await paymentService.cancel(transactionID, reason: "unknown")
                }
            }
        }
    }
}
```

> Important: Design your cancellation handlers to finish their tasks quickly. On all
> platforms except macOS, the system can still suspend the process shortly after cancellation.
> However, supporting this protocol provides additional time compared to app intents that
> don’t support this protocol.

## Topics

### Cancelling the intent

[`withIntentCancellationHandler(operation:onCancel:isolation:)`](/documentation/AppIntents/CancellableIntent/withIntentCancellationHandler(operation:onCancel:isolation:))

Runs an operation with a cancellation handler that receives a cancellation reason.

[`IntentCancellationReason`](/documentation/AppIntents/IntentCancellationReason)

Reasons for the cancellation of an app intent’s operation.

## Relationships

### Inherits From

[`AppIntent`](/documentation/AppIntents/AppIntent)

[`Sendable`](/documentation/Swift/Sendable)

[`PersistentlyIdentifiable`](/documentation/AppIntents/PersistentlyIdentifiable)

[`SendableMetatype`](/documentation/Swift/SendableMetatype)

---

Copyright &copy; 2026 Apple Inc. All rights reserved. | [Terms of Use](https://www.apple.com/legal/internet-services/terms/site.html) | [Privacy Policy](https://www.apple.com/privacy/privacy-policy)