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

# Cancel Payment Intent

> Cancel a pending payment intent before it is processed or expires

## Overview

The Cancel Payment Intent endpoint allows you to cancel a pending payment intent before the terminal processes the card payment or the intent expires. Once cancelled, the terminal will be notified and the payment request is withdrawn.

**Common use cases:**

* Customer decides not to pay at the terminal
* Order was entered with incorrect amount or details
* User navigates away from the payment screen in your application
* A new payment intent needs to replace an existing one

<Warning>
  Cancellation is **permanent and irreversible**. Once a payment intent is cancelled, it cannot be reactivated. Create a new payment intent if payment is still needed.
</Warning>

## Authentication

This endpoint requires API key authentication using the `x-api-key` header.

## Cancellation Rules

You can only cancel a payment intent if **all** of these conditions are met:

<Steps>
  <Step title="Status is PENDING">
    The payment intent must be in `PENDING` status. You cannot cancel payment intents that are already `CONFIRMED` or `CANCELLED`.
  </Step>

  <Step title="Payment intent belongs to your organization">
    You can only cancel payment intents created by your organization.
  </Step>
</Steps>

<Note>
  If a `terminalCode` was provided when creating the payment intent, cancelling it also notifies the terminal that the payment request has been withdrawn.
</Note>

## Request Format

```
POST /api/payment-intent/{id}/cancel
```

**API reference:** [`POST /payment-intent/{id}/cancel`](/api-reference/payment-intent/cancel)

<ParamField path="id" type="string" required>
  The unique identifier (UUID) of the payment intent to cancel.
</ParamField>

## Response Format

The endpoint returns an empty JSON object on success:

```json theme={null}
{}
```

## Examples

### Cancel a payment intent

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST 'https://api.harmony.compago.com/api/payment-intent/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cancel' \
    -H 'x-api-key: YOUR_API_KEY'
  ```

  ```javascript Node.js theme={null}
  const paymentIntentId = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee';

  const response = await fetch(
    `https://api.harmony.compago.com/api/payment-intent/${paymentIntentId}/cancel`,
    {
      method: 'POST',
      headers: { 'x-api-key': 'YOUR_API_KEY' }
    }
  );

  if (response.ok) {
    console.log('Payment intent cancelled successfully');
  } else {
    const error = await response.json();
    console.error('Failed to cancel:', error.message);
  }
  ```

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

  payment_intent_id = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'

  response = requests.post(
      f'https://api.harmony.compago.com/api/payment-intent/{payment_intent_id}/cancel',
      headers={'x-api-key': 'YOUR_API_KEY'}
  )

  if response.status_code == 200:
      print('Payment intent cancelled successfully')
  else:
      print(f'Failed to cancel: {response.text}')
  ```

  ```php PHP theme={null}
  <?php
  $paymentIntentId = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee';

  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, "https://api.harmony.compago.com/api/payment-intent/{$paymentIntentId}/cancel");
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_HTTPHEADER, [
      'x-api-key: YOUR_API_KEY'
  ]);

  $response = curl_exec($ch);
  $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  curl_close($ch);

  if ($httpCode === 200) {
      echo "Payment intent cancelled successfully\n";
  } else {
      echo "Failed to cancel: {$response}\n";
  }
  ?>
  ```
</CodeGroup>

### Cancel with error handling

<CodeGroup>
  ```javascript Node.js theme={null}
  async function cancelPaymentIntent(paymentIntentId) {
    try {
      const response = await fetch(
        `https://api.harmony.compago.com/api/payment-intent/${paymentIntentId}/cancel`,
        {
          method: 'POST',
          headers: { 'x-api-key': 'YOUR_API_KEY' }
        }
      );

      if (!response.ok) {
        if (response.status === 404) {
          throw new Error('Payment intent not found');
        } else if (response.status === 400) {
          const error = await response.json();
          throw new Error(`Cannot cancel: ${error.message}`);
        } else if (response.status === 401) {
          throw new Error('Invalid API key');
        }
        throw new Error(`Unexpected error: ${response.status}`);
      }

      return true;
    } catch (error) {
      console.error('Error cancelling payment intent:', error.message);
      throw error;
    }
  }

  // Usage
  try {
    await cancelPaymentIntent('aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee');
    console.log('Successfully cancelled');
  } catch (error) {
    console.error('Cancellation failed:', error.message);
  }
  ```

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

  def cancel_payment_intent(payment_intent_id):
      try:
          response = requests.post(
              f'https://api.harmony.compago.com/api/payment-intent/{payment_intent_id}/cancel',
              headers={'x-api-key': 'YOUR_API_KEY'}
          )

          if response.status_code == 404:
              raise ValueError('Payment intent not found')
          elif response.status_code == 400:
              error_data = response.json()
              raise ValueError(f"Cannot cancel: {error_data.get('message')}")
          elif response.status_code == 401:
              raise ValueError('Invalid API key')
          elif response.status_code != 200:
              raise ValueError(f'Unexpected error: {response.status_code}')

          return True
      except requests.exceptions.RequestException as e:
          print(f'Request error: {e}')
          raise

  # Usage
  try:
      cancel_payment_intent('aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee')
      print('Successfully cancelled')
  except ValueError as e:
      print(f'Cancellation failed: {e}')
  ```
</CodeGroup>

## Error Responses

<ResponseField name="400" type="error">
  **Cannot cancel payment intent** - The payment intent is not in `PENDING` status.

  Common reasons:

  * Payment intent status is `CONFIRMED` (already paid)
  * Payment intent status is `CANCELLED` (already cancelled)
</ResponseField>

<ResponseField name="404" type="error">
  **Payment intent not found** - No payment intent with the specified ID exists in your organization.
</ResponseField>

<ResponseField name="401" type="error">
  **Unauthorized** - Missing or invalid API key.
</ResponseField>

## What Happens After Cancellation

After a payment intent is successfully cancelled:

1. **Status Change**: The status changes from `PENDING` to `CANCELLED`
2. **Terminal Notification**: The associated terminal (if any) is notified
3. **Return to Your App**: If the payment intent was created with a `redirectAppId`, the terminal returns to that app after showing the cancellation screen
4. **Irreversible**: The cancellation cannot be undone
5. **New Intent Required**: If payment is still needed, create a new payment intent

## Next Steps

<CardGroup cols={2}>
  <Card title="Create Payment Intent" icon="plus" href="/payment-intent/create">
    Create a new payment intent to replace the cancelled one
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference/payment-intent/cancel">
    View the full API reference for the cancel endpoint
  </Card>
</CardGroup>
