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

# Cancel Payment

> Cancel a pending payment before the customer completes the payment.

# Cancel Payment

The Cancel Payment API allows you to cancel a payment that is still awaiting customer action.

A payment can only be cancelled while it is in a **pending** state. Once a payment has been completed, failed, expired, or previously cancelled, it can no longer be cancelled.

> **Note**
> Cancellation only prevents the customer from completing the payment. If the payment has already been processed successfully, use refunds or reversals where applicable.

***

## Endpoint

```http theme={null}
POST /payments/cancel
```

***

## Authentication

Every request must include your API credentials.

| Header       | Required | Description         |
| ------------ | :------: | ------------------- |
| X-API-KEY    |     ✅    | Merchant API Key    |
| X-API-SECRET |     ✅    | Merchant API Secret |
| Content-Type |     ✅    | application/json    |

***

## Example Request

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl --request POST \
      --url https://api.splashpay.co.tz/api/v1/payments/cancel \
      --header "Content-Type: application/json" \
      --header "X-API-KEY: pk_live_xxxxxxxxx" \
      --header "X-API-SECRET: sk_live_xxxxxxxxx" \
      --data '{
        "reference": "CIR-6723dg"
    }'
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    const response = await fetch(
      "https://api.splashpay.co.tz/api/v1/payments/cancel",
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-API-KEY": process.env.SPLASHPAY_KEY,
          "X-API-SECRET": process.env.SPLASHPAY_SECRET,
        },
        body: JSON.stringify({
          reference: "CIR-6723dg",
        }),
      }
    );

    const data = await response.json();
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import requests

    response = requests.post(
        "https://api.splashpay.co.tz/api/v1/payments/cancel",
        headers={
            "Content-Type": "application/json",
            "X-API-KEY": "pk_live_xxxxxxxxx",
            "X-API-SECRET": "sk_live_xxxxxxxxx",
        },
        json={
            "reference": "CIR-6723dg"
        }
    )

    print(response.json())
    ```
  </Tab>

  <Tab title="PHP">
    ```php theme={null}
    $client = new \GuzzleHttp\Client();

    $response = $client->post(
        'https://api.splashpay.co.tz/api/v1/payments/cancel',
        [
            'headers' => [
                'Content-Type' => 'application/json',
                'X-API-KEY' => 'pk_live_xxxxxxxxx',
                'X-API-SECRET' => 'sk_live_xxxxxxxxx',
            ],
            'json' => [
                'reference' => 'CIR-6723dg',
            ],
        ]
    );

    echo $response->getBody();
    ```
  </Tab>
</Tabs>

***

## Request Body

| Field     | Type   | Required | Description                                                              |
| --------- | ------ | :------: | ------------------------------------------------------------------------ |
| reference | string |     ✅    | Unique merchant payment reference returned when the payment was created. |

***

## Example Response

```json theme={null}
{
    "status": "success",
    "code": "PAYMENT_CANCELLED",
    "message": "Payment cancelled successfully",
    "data": {
        "reference": "CIR-6723e8hs6",
        "provider_reference": "S20629971309",
        "status": "cancelled",
        "cancelled_at": "2026-07-12 11:01:56"
    },
    "meta": [],
    "request_id": "05ae240d-f77f-4cff-a8c5-b4bc09e92b32"
}
```

***

## Error Responses

### Payment Already Completed

```json theme={null}
{
    "status": "error",
    "code": "PAYMENT_NOT_CANCELLABLE",
    "message": "Payment cannot be cancelled because it has already been completed."
}
```

### Payment Expired

```json theme={null}
{
    "status": "error",
    "code": "PAYMENT_NOT_CANCELLABLE",
    "message": "Payment cannot be cancelled because it has expired."
}
```

### Payment Not Found

```json theme={null}
{
    "status": "error",
    "code": "PAYMENT_NOT_FOUND",
    "message": "Payment not found."
}
```

***

## Cancellable Statuses

| Payment Status |                 Can Cancel                 |
| -------------- | :----------------------------------------: |
| `pending`      |                      ✅                     |
| `processing`   | ✅ *(if supported by the payment provider)* |
| `success`      |                      ❌                     |
| `failed`       |                      ❌                     |
| `expired`      |                      ❌                     |
| `cancelled`    |                      ❌                     |

***

## Webhook Notification

If your merchant account has a webhook endpoint configured, SplashPay sends a **`payment.cancelled`** event after the payment has been successfully cancelled.

The webhook is dispatched only after the cancellation has been confirmed and the transaction has been updated in SplashPay.

### Event

```text theme={null}
payment.cancelled
```

### Sample Webhook

```json theme={null}
{
  "event": "payment.cancelled",
  "created_at": "2026-07-12T11:01:56Z",
  "data": {
    "reference": "CIR-6723e8hs6",
    "provider_reference": "S20629971309",
    "amount": "1000.00",
    "currency": "TZS",
    "status": "cancelled",
    "payment_method": "tanqr",
    "provider": "selcom",
    "channel": "tanqr",
    "network": "SELCOMTANQR",
    "cancelled_at": "2026-07-12T11:01:56Z"
  }
}
```

## Best Practices

<Steps>
  <Step title="Cancel only pending payments">
    Call the Cancel Payment endpoint before the customer completes the payment. Once payment is successful, it cannot be cancelled.
  </Step>

  <Step title="Use the merchant reference">
    Always store the merchant reference returned when creating the payment. It is required to cancel or check the payment status.
  </Step>

  <Step title="Verify the final status">
    After cancelling a payment, you can use the **Check Payment Status** endpoint to confirm that the payment status is `cancelled`.
  </Step>

  <Step title="Handle webhook notifications">
    If your application receives webhook events, update your local payment record whenever a `payment.cancelled` event is received.
  </Step>
</Steps>

***

## Related Guides

<CardGroup cols={2}>
  <Card title="Check Payment Status" href="/collections/status" icon="clock">
    Retrieve the latest status of a payment.
  </Card>

  <Card title="Webhooks" href="/collections/webhooks" icon="webhook">
    Receive real-time payment events.
  </Card>

  <Card title="Mobile Money" href="/collections/mobile-money" icon="smartphone">
    Accept Mobile Money payments.
  </Card>

  <Card title="Dynamic TanQR" href="/collections/tanqr" icon="qr-code">
    Accept payments using Dynamic TanQR.
  </Card>
</CardGroup>
