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

# Card Payment

> Country-specific information for card payments and subscriptions in Colombia.

# Colombia - Card Payment

This section provides Colombia-specific information about using the Card Payment API to manage subscriptions with credit and debit cards.

## Availability

The Card Payment API is available in Colombia to process recurring payments with credit and debit cards issued by Colombian and international banks.

## Accepted Documents

To create subscriptions and process card payments in Colombia, the following document types are accepted:

| Type  | Description                         |
| ----- | ----------------------------------- |
| `CC`  | Cédula de Ciudadanía                |
| `CE`  | Cédula de Extranjería               |
| `NIT` | Número de Identificación Tributaria |
| `TI`  | Tarjeta de Identidad                |
| `PAS` | Pasaporte                           |

## Supported Currencies

| Code  | Currency       |
| ----- | -------------- |
| `COP` | Colombian Peso |

## Subscription Periodicity

Subscriptions in Colombia support the following periodicities:

| Periodicity       | Description                                   |
| ----------------- | --------------------------------------------- |
| `daily`           | Recurring daily payments                      |
| `weekly`          | Recurring weekly payments                     |
| `biweekly`        | Recurring biweekly payments                   |
| `monthly`         | Recurring monthly payments                    |
| `threefortnights` | Recurring every three fortnights              |
| `bimonthly`       | Recurring bimonthly payments                  |
| `quarterly`       | Recurring quarterly payments                  |
| `fourmonths`      | Recurring every four months                   |
| `halfyearly`      | Recurring every six months                    |
| `yearly`          | Recurring yearly payments                     |
| `custom`          | Custom periodicity according to configuration |

## Workflow

### 1. Create Subscription

First, create a subscription by associating a card with a recurring payment plan. The card token must be obtained through the TumiPay SDK.

### 2. Preauthorize Transactions

For each payment cycle, preauthorize the corresponding amount. This reserves funds without making the actual charge.

### 3. Capture Transactions

Once preauthorized, capture the transaction to perform the actual charge to the customer's card.

### 4. Automatic Renewal

For recurring subscriptions, use the renewal preauthorization endpoint to process payments in each cycle.

## Special Considerations

### 3D Secure (3DS)

Some card transactions may require 3D Secure authentication. The system automatically handles this process when necessary.

### Transaction Limits

Transaction limits may vary depending on the card type and issuing bank. Contact the support team to learn about the specific limits applicable to your account.

### International Cards

Cards issued by international banks are accepted, as long as they are compatible with the processing networks available in Colombia.

## Examples

### Create Subscription

<CodeGroup dropdown>
  ```bash cURL theme={null}
  curl --request POST 'https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card' \
  --header 'Token-Top: your_auth_token' \
  --header 'Authorization: Basic your_auth_key' \
  --header 'X-Merchant-ID: your_merchant_id' \
  --header 'X-Request-ID: your-request-id' \
  --header 'Content-Type: application/json' \
  --data-raw '{
      "token": "card_token_abc123",
      "plan_name": "Plan Premium",
      "periodicity": "monthly",
      "customer_data": {
          "legal_doc": "1234567890",
          "legal_doc_type": "CC",
          "phone_code": "+57",
          "phone_number": "3121234567",
          "email": "customer@example.com",
          "full_name": "John Doe"
      },
      "start_date": "2026-01-01"
  }'
  ```

  ```typescript TypeScript theme={null}
  import axios from 'axios';

  const createSubscription = async () => {
    try {
      const response = await axios.post('https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card', {
        token: 'card_token_abc123',
        plan_name: 'Plan Premium',
        periodicity: 'monthly',
        customer_data: {
          legal_doc: '1234567890',
          legal_doc_type: 'CC',
          phone_code: '+57',
          phone_number: '3121234567',
          email: 'customer@example.com',
          full_name: 'John Doe'
        },
        start_date: '2026-01-01'
      }, {
        headers: {
          'Token-Top': 'your_auth_token',
          'Authorization': 'Basic your_auth_key',
          'X-Merchant-ID': 'your_merchant_id',
          'X-Request-ID': 'your-request-id',
          'Content-Type': 'application/json'
        }
      });
      console.log(response.data);
    } catch (error) {
      console.error(error);
    }
  };

  createSubscription();
  ```

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

  url = "https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card"

  headers = {
      'Token-Top': 'your_auth_token',
      'Authorization': 'Basic your_auth_key',
      'X-Merchant-ID': 'your_merchant_id',
      'X-Request-ID': 'your-request-id',
      'Content-Type': 'application/json'
  }

  payload = {
      "token": "card_token_abc123",
      "plan_name": "Plan Premium",
      "periodicity": "monthly",
      "customer_data": {
          "legal_doc": "1234567890",
          "legal_doc_type": "CC",
          "phone_code": "+57",
          "phone_number": "3121234567",
          "email": "customer@example.com",
          "full_name": "John Doe"
      },
      "start_date": "2026-01-01"
  }

  response = requests.post(url, headers=headers, data=json.dumps(payload))
  result = response.json()
  ```

  ```php PHP theme={null}
  <?php
  $curl = curl_init();

  curl_setopt_array($curl, array(
    CURLOPT_URL => 'https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => '',
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 0,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_POSTFIELDS =>'{
      "token": "card_token_abc123",
      "plan_name": "Plan Premium",
      "periodicity": "monthly",
      "customer_data": {
          "legal_doc": "1234567890",
          "legal_doc_type": "CC",
          "phone_code": "+57",
          "phone_number": "3121234567",
          "email": "customer@example.com",
          "full_name": "John Doe"
      },
      "start_date": "2026-01-01"
  }',
    CURLOPT_HTTPHEADER => array(
      'Token-Top: your_auth_token',
      'Authorization: Basic your_auth_key',
      'X-Merchant-ID: your_merchant_id',
      'X-Request-ID: your-request-id',
      'Content-Type: application/json'
    ),
  ));

  $response = curl_exec($curl);

  curl_close($curl);
  echo $response;
  ?>
  ```

  ```java Java theme={null}
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;
  import java.net.URI;
  import java.io.IOException;

  public class CreateSubscription {
      public static void main(String[] args) throws IOException, InterruptedException {
          HttpClient client = HttpClient.newHttpClient();
          String json = "{ \"token\": \"card_token_abc123\", \"plan_name\": \"Plan Premium\", \"periodicity\": \"monthly\", \"customer_data\": { \"legal_doc\": \"1234567890\", \"legal_doc_type\": \"CC\", \"phone_code\": \"+57\", \"phone_number\": \"3121234567\", \"email\": \"customer@example.com\", \"full_name\": \"John Doe\" }, \"start_date\": \"2026-01-01\" }";

          HttpRequest request = HttpRequest.newBuilder()
                  .uri(URI.create("https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card"))
                  .header("Token-Top", "your_auth_token")
                  .header("Authorization", "Basic your_auth_key")
                  .header("X-Merchant-ID", "your_merchant_id")
                  .header("X-Request-ID", "your-request-id")
                  .header("Content-Type", "application/json")
                  .POST(HttpRequest.BodyPublishers.ofString(json))
                  .build();

          HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

          System.out.println(response.body());
      }
  }
  ```

  ```go Go theme={null}
  package main

  import (
      "fmt"
      "net/http"
      "io/ioutil"
      "strings"
  )

  func main() {
      url := "https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card"
      method := "POST"

      payload := strings.NewReader(`{
          "token": "card_token_abc123",
          "plan_name": "Plan Premium",
          "periodicity": "monthly",
          "customer_data": {
              "legal_doc": "1234567890",
              "legal_doc_type": "CC",
              "phone_code": "+57",
              "phone_number": "3121234567",
              "email": "customer@example.com",
              "full_name": "John Doe"
          },
          "start_date": "2026-01-01"
      }`)

      client := &http.Client {}
      req, err := http.NewRequest(method, url, payload)

      if err != nil {
          fmt.Println(err)
          return
      }
      req.Header.Add("Token-Top", "your_auth_token")
      req.Header.Add("Authorization", "Basic your_auth_key")
      req.Header.Add("X-Merchant-ID", "your_merchant_id")
      req.Header.Add("X-Request-ID", "your-request-id")
      req.Header.Add("Content-Type", "application/json")

      res, err := client.Do(req)
      if err != nil {
          fmt.Println(err)
          return
      }
      defer res.Body.Close()

      body, err := ioutil.ReadAll(res.Body)
      if err != nil {
          fmt.Println(err)
          return
      }
      fmt.Println(string(body))
  }
  ```
</CodeGroup>

### Response

```json theme={null}
{
    "code": "CREATED",
    "status": true,
    "message": "Suscripción creada exitosamente",
    "data": {
        "subscription_id": "550e8400-e29b-41d4-a716-446655440000"
    }
}
```

***

### Authorize Payment

Pre-authorizes an amount for a subscription. Funds are reserved on the card but not charged until a capture is performed.

<CodeGroup dropdown>
  ```bash cURL theme={null}
  curl --request POST 'https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card/authorize' \
  --header 'Token-Top: your_auth_token' \
  --header 'Authorization: Basic your_auth_key' \
  --header 'X-Merchant-ID: your_merchant_id' \
  --header 'X-Request-ID: your-request-id' \
  --header 'Content-Type: application/json' \
  --data-raw '{
      "reference_id": "e8096427-c006-4342-acf2-962edde6477e",
      "subscription_id": "550e8400-e29b-41d4-a716-446655440000",
      "currency": "COP",
      "amount": 400000,
      "tax": 63874
  }'
  ```

  ```typescript TypeScript theme={null}
  import axios from 'axios';

  const authorizePayment = async () => {
    try {
      const response = await axios.post('https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card/authorize', {
        reference_id: 'e8096427-c006-4342-acf2-962edde6477e',
        subscription_id: '550e8400-e29b-41d4-a716-446655440000',
        currency: 'COP',
        amount: 400000,
        tax: 63874
      }, {
        headers: {
          'Token-Top': 'your_auth_token',
          'Authorization': 'Basic your_auth_key',
          'X-Merchant-ID': 'your_merchant_id',
          'X-Request-ID': 'your-request-id',
          'Content-Type': 'application/json'
        }
      });
      console.log(response.data);
    } catch (error) {
      console.error(error);
    }
  };

  authorizePayment();
  ```

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

  url = "https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card/authorize"

  headers = {
      'Token-Top': 'your_auth_token',
      'Authorization': 'Basic your_auth_key',
      'X-Merchant-ID': 'your_merchant_id',
      'X-Request-ID': 'your-request-id',
      'Content-Type': 'application/json'
  }

  payload = {
      "reference_id": "e8096427-c006-4342-acf2-962edde6477e",
      "subscription_id": "550e8400-e29b-41d4-a716-446655440000",
      "currency": "COP",
      "amount": 400000,
      "tax": 63874
  }

  response = requests.post(url, headers=headers, data=json.dumps(payload))
  result = response.json()
  ```

  ```php PHP theme={null}
  <?php
  $curl = curl_init();

  curl_setopt_array($curl, array(
    CURLOPT_URL => 'https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card/authorize',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_POSTFIELDS => '{
      "reference_id": "e8096427-c006-4342-acf2-962edde6477e",
      "subscription_id": "550e8400-e29b-41d4-a716-446655440000",
      "currency": "COP",
      "amount": 400000,
      "tax": 63874
  }',
    CURLOPT_HTTPHEADER => array(
      'Token-Top: your_auth_token',
      'Authorization: Basic your_auth_key',
      'X-Merchant-ID: your_merchant_id',
      'X-Request-ID: your-request-id',
      'Content-Type: application/json'
    ),
  ));

  $response = curl_exec($curl);
  curl_close($curl);
  echo $response;
  ?>
  ```
</CodeGroup>

#### Response

```json theme={null}
{
    "code": "AUTHORIZED",
    "status": true,
    "message": "Pago autorizado exitosamente",
    "data": {
        "transaction_id": "7f45a9da-2f84-4103-ac54-05fe8ea693ca",
        "transaction_date": "2026-01-01T10:00:00Z",
        "transaction_status": "APPROVED",
        "transaction_type": "PRE_AUTH_TRANSACTION",
        "reference_id": "e8096427-c006-4342-acf2-962edde6477e",
        "amount": 400000,
        "currency": "COP"
    }
}
```

<Info>
  Use the `transaction_id` from this response in the subsequent capture or renewal requests.
</Info>

***

### Renew Authorization

Preauthorizes an amount for a subscription renewal cycle. This endpoint requires a previous pre-authorization transaction (`linked_transaction_id`). The original transaction is automatically cancelled after the renewal is processed.

<CodeGroup dropdown>
  ```bash cURL theme={null}
  curl --request POST 'https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card/authorize/renewal' \
  --header 'Token-Top: your_auth_token' \
  --header 'Authorization: Basic your_auth_key' \
  --header 'X-Merchant-ID: your_merchant_id' \
  --header 'X-Request-ID: your-request-id' \
  --header 'Content-Type: application/json' \
  --data-raw '{
      "reference_id": "f9107538-d117-5453-bdf3-073fed7e588f",
      "subscription_id": "550e8400-e29b-41d4-a716-446655440000",
      "currency": "COP",
      "amount": 400000,
      "tax": 63874,
      "linked_transaction_id": "7f45a9da-2f84-4103-ac54-05fe8ea693ca"
  }'
  ```

  ```typescript TypeScript theme={null}
  import axios from 'axios';

  const renewAuthorization = async () => {
    try {
      const response = await axios.post('https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card/authorize/renewal', {
        reference_id: 'f9107538-d117-5453-bdf3-073fed7e588f',
        subscription_id: '550e8400-e29b-41d4-a716-446655440000',
        currency: 'COP',
        amount: 400000,
        tax: 63874,
        linked_transaction_id: '7f45a9da-2f84-4103-ac54-05fe8ea693ca'
      }, {
        headers: {
          'Token-Top': 'your_auth_token',
          'Authorization': 'Basic your_auth_key',
          'X-Merchant-ID': 'your_merchant_id',
          'X-Request-ID': 'your-request-id',
          'Content-Type': 'application/json'
        }
      });
      console.log(response.data);
    } catch (error) {
      console.error(error);
    }
  };

  renewAuthorization();
  ```

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

  url = "https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card/authorize/renewal"

  headers = {
      'Token-Top': 'your_auth_token',
      'Authorization': 'Basic your_auth_key',
      'X-Merchant-ID': 'your_merchant_id',
      'X-Request-ID': 'your-request-id',
      'Content-Type': 'application/json'
  }

  payload = {
      "reference_id": "f9107538-d117-5453-bdf3-073fed7e588f",
      "subscription_id": "550e8400-e29b-41d4-a716-446655440000",
      "currency": "COP",
      "amount": 400000,
      "tax": 63874,
      "linked_transaction_id": "7f45a9da-2f84-4103-ac54-05fe8ea693ca"
  }

  response = requests.post(url, headers=headers, data=json.dumps(payload))
  result = response.json()
  ```

  ```php PHP theme={null}
  <?php
  $curl = curl_init();

  curl_setopt_array($curl, array(
    CURLOPT_URL => 'https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card/authorize/renewal',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_POSTFIELDS => '{
      "reference_id": "f9107538-d117-5453-bdf3-073fed7e588f",
      "subscription_id": "550e8400-e29b-41d4-a716-446655440000",
      "currency": "COP",
      "amount": 400000,
      "tax": 63874,
      "linked_transaction_id": "7f45a9da-2f84-4103-ac54-05fe8ea693ca"
  }',
    CURLOPT_HTTPHEADER => array(
      'Token-Top: your_auth_token',
      'Authorization: Basic your_auth_key',
      'X-Merchant-ID: your_merchant_id',
      'X-Request-ID: your-request-id',
      'Content-Type: application/json'
    ),
  ));

  $response = curl_exec($curl);
  curl_close($curl);
  echo $response;
  ?>
  ```
</CodeGroup>

#### Response

```json theme={null}
{
    "code": "AUTHORIZED",
    "status": true,
    "message": "Renovación de pago autorizada exitosamente",
    "data": {
        "transaction_id": "9b8a7c6d-5e4f-3a2b-1c0d-e9f8a7b6c5d4",
        "transaction_date": "2026-02-01T10:00:00Z",
        "linked_transaction_id": "7f45a9da-2f84-4103-ac54-05fe8ea693ca",
        "transaction_status": "APPROVED",
        "transaction_type": "RENEWAL_PRE_AUTH_TRANSACTION",
        "reference_id": "f9107538-d117-5453-bdf3-073fed7e588f",
        "amount": 400000,
        "currency": "COP"
    }
}
```

***

### Capture Transaction

Captures a previously pre-authorized transaction. This performs the actual charge to the customer's card.

<Warning>
  Si el monto a capturar supera en más de un **10%** el monto originalmente preautorizado, Kushki rechaza la operación y el sistema devuelve **HTTP 400** con el siguiente error:

  ```json theme={null}
  {
    "code": "PROCESSING_ERROR",
    "status": false,
    "message": "El monto de captura es inválido. Por favor, verifique el monto y vuelva a intentarlo."
  }
  ```

  En ese caso, cancele la preautorización actual y genere una nueva Renovación (`/api/subscription/card/authorize/renewal`) con el monto actualizado antes de proceder al capture.
</Warning>

<CodeGroup dropdown>
  ```bash cURL theme={null}
  curl --request POST 'https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card/capture' \
  --header 'Token-Top: your_auth_token' \
  --header 'Authorization: Basic your_auth_key' \
  --header 'X-Merchant-ID: your_merchant_id' \
  --header 'X-Request-ID: your-request-id' \
  --header 'Content-Type: application/json' \
  --data-raw '{
      "transaction_id": "7f45a9da-2f84-4103-ac54-05fe8ea693ca",
      "amount": 400000,
      "tax": 63874
  }'
  ```

  ```typescript TypeScript theme={null}
  import axios from 'axios';

  const captureTransaction = async () => {
    try {
      const response = await axios.post('https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card/capture', {
        transaction_id: '7f45a9da-2f84-4103-ac54-05fe8ea693ca',
        amount: 400000,
        tax: 63874
      }, {
        headers: {
          'Token-Top': 'your_auth_token',
          'Authorization': 'Basic your_auth_key',
          'X-Merchant-ID': 'your_merchant_id',
          'X-Request-ID': 'your-request-id',
          'Content-Type': 'application/json'
        }
      });
      console.log(response.data);
    } catch (error) {
      console.error(error);
    }
  };

  captureTransaction();
  ```

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

  url = "https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card/capture"

  headers = {
      'Token-Top': 'your_auth_token',
      'Authorization': 'Basic your_auth_key',
      'X-Merchant-ID': 'your_merchant_id',
      'X-Request-ID': 'your-request-id',
      'Content-Type': 'application/json'
  }

  payload = {
      "transaction_id": "7f45a9da-2f84-4103-ac54-05fe8ea693ca",
      "amount": 400000,
      "tax": 63874
  }

  response = requests.post(url, headers=headers, data=json.dumps(payload))
  result = response.json()
  ```

  ```php PHP theme={null}
  <?php
  $curl = curl_init();

  curl_setopt_array($curl, array(
    CURLOPT_URL => 'https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card/capture',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_POSTFIELDS => '{
      "transaction_id": "7f45a9da-2f84-4103-ac54-05fe8ea693ca",
      "amount": 400000,
      "tax": 63874
  }',
    CURLOPT_HTTPHEADER => array(
      'Token-Top: your_auth_token',
      'Authorization: Basic your_auth_key',
      'X-Merchant-ID: your_merchant_id',
      'X-Request-ID: your-request-id',
      'Content-Type: application/json'
    ),
  ));

  $response = curl_exec($curl);
  curl_close($curl);
  echo $response;
  ?>
  ```
</CodeGroup>

#### Response

```json theme={null}
{
    "code": "CAPTURED",
    "status": true,
    "message": "Pago capturado exitosamente",
    "data": {
        "transaction_id": "2c3d4e5f-6a7b-8c9d-0e1f-2a3b4c5d6e7f",
        "linked_transaction_id": "7f45a9da-2f84-4103-ac54-05fe8ea693ca",
        "transaction_date": "2026-01-01T12:00:00Z",
        "transaction_status": "APPROVED",
        "transaction_type": "COMPLETION_TRANSACTION",
        "reference_id": "e8096427-c006-4342-acf2-962edde6477e",
        "amount": 400000,
        "currency": "COP"
    }
}
```

<Warning>
  A transaction can only be captured once. Attempting to capture an already-captured transaction returns **HTTP 409** with code `TRANSACTION_ALREADY_CAPTURED`.
</Warning>

***

### Cancel Subscription

Cancels an active or paused subscription. This operation is idempotent: if the subscription is already cancelled, the system returns `ALREADY_CANCELLED` without error.

<CodeGroup dropdown>
  ```bash cURL theme={null}
  curl --request POST 'https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card/cancel' \
  --header 'Token-Top: your_auth_token' \
  --header 'Authorization: Basic your_auth_key' \
  --header 'X-Merchant-ID: your_merchant_id' \
  --header 'X-Request-ID: your-request-id' \
  --header 'Content-Type: application/json' \
  --data-raw '{
      "subscription_id": "550e8400-e29b-41d4-a716-446655440000"
  }'
  ```

  ```typescript TypeScript theme={null}
  import axios from 'axios';

  const cancelSubscription = async () => {
    try {
      const response = await axios.post('https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card/cancel', {
        subscription_id: '550e8400-e29b-41d4-a716-446655440000'
      }, {
        headers: {
          'Token-Top': 'your_auth_token',
          'Authorization': 'Basic your_auth_key',
          'X-Merchant-ID': 'your_merchant_id',
          'X-Request-ID': 'your-request-id',
          'Content-Type': 'application/json'
        }
      });
      console.log(response.data);
    } catch (error) {
      console.error(error);
    }
  };

  cancelSubscription();
  ```

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

  url = "https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card/cancel"

  headers = {
      'Token-Top': 'your_auth_token',
      'Authorization': 'Basic your_auth_key',
      'X-Merchant-ID': 'your_merchant_id',
      'X-Request-ID': 'your-request-id',
      'Content-Type': 'application/json'
  }

  payload = {
      "subscription_id": "550e8400-e29b-41d4-a716-446655440000"
  }

  response = requests.post(url, headers=headers, data=json.dumps(payload))
  result = response.json()
  ```

  ```php PHP theme={null}
  <?php
  $curl = curl_init();

  curl_setopt_array($curl, array(
    CURLOPT_URL => 'https://tumipay-card-payments.staging.topup.com.co/production/api/subscription/card/cancel',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_POSTFIELDS => '{
      "subscription_id": "550e8400-e29b-41d4-a716-446655440000"
  }',
    CURLOPT_HTTPHEADER => array(
      'Token-Top: your_auth_token',
      'Authorization: Basic your_auth_key',
      'X-Merchant-ID: your_merchant_id',
      'X-Request-ID: your-request-id',
      'Content-Type: application/json'
    ),
  ));

  $response = curl_exec($curl);
  curl_close($curl);
  echo $response;
  ?>
  ```
</CodeGroup>

#### Response

```json theme={null}
{
    "code": "SUCCESS",
    "status": true,
    "message": "Suscripción cancelada exitosamente",
    "data": {
        "subscription_id": "550e8400-e29b-41d4-a716-446655440000",
        "cancellation_date": "2026-01-15T10:00:00.000Z"
    }
}
```

#### Already Cancelled Response

```json theme={null}
{
    "code": "ALREADY_CANCELLED",
    "status": true,
    "message": "La suscripción ya estaba cancelada",
    "data": {
        "subscription_id": "550e8400-e29b-41d4-a716-446655440000",
        "cancellation_date": "2026-01-10T10:00:00.000Z"
    }
}
```

***

## Webhooks

TumiPay Card Payments sends webhooks to notify your system about important events in the payment lifecycle. Webhooks allow you to receive real-time updates about transactions and subscriptions without polling the API.

<Card title="What are Webhooks?" icon="question-circle">
  Webhooks are HTTP callbacks that automatically notify your application when specific events occur, such as transaction authorizations, captures, or subscription status changes.
</Card>

### Available Events

TumiPay Card Payments sends webhooks for the following events in Colombia:

<CardGroup cols={2}>
  <Card title="Transaction Events" icon="credit-card">
    * `transaction.authorized` - Transaction successfully authorized
    * `transaction.captured` - Transaction successfully captured
    * `transaction.declined` - Transaction declined by provider
  </Card>

  <Card title="Subscription Events" icon="repeat">
    * `subscription.created` - Subscription successfully created
    * `subscription.cancelled` - Subscription cancelled
    * `subscription.expired` - Subscription expired
  </Card>
</CardGroup>

### Webhook Configuration

Before receiving webhooks, you must configure your webhook endpoint. To configure webhooks for Card Payment, please contact the support team.

<Card title="How to Configure Webhooks" icon="envelope">
  To set up webhook notifications, you need to:

  1. **Contact Support**: Send an email to [soporte@tumipay.co](mailto:soporte@tumipay.co) or request assistance through the support channel
  2. **Provide Your Webhook URL**: Your HTTPS endpoint where webhooks will be sent (must be publicly accessible)
  3. **Receive Secret Key**: You will receive a shared secret key used to sign and verify webhook payloads
  4. **Activation**: The support team will activate webhook delivery for your account
</Card>

<Info>
  For webhook configuration assistance, contact:

  * **Support Email**: [soporte@tumipay.co](mailto:soporte@tumipay.co)
  * **Technical Email**: [tecnologia@tumipay.co](mailto:tecnologia@tumipay.co)
</Info>

<Warning>
  Your webhook URL must use HTTPS. TumiPay will only send webhooks to secure endpoints.
</Warning>

### Security

All webhooks are signed using HMAC SHA256. You must verify the signature in the `X-Webhook-Signature` header before processing any webhook to ensure authenticity.

<Tip>
  Always verify webhook signatures to prevent unauthorized requests. Use constant-time comparison functions to prevent timing attacks.
</Tip>

### Idempotency

Webhooks include an `idempotency_key` in both the payload and the `X-Idempotency-Key` header. Use this key to detect and handle duplicate webhook deliveries.

**Format**: `{event_type}:{entity_uuid}`

**Example**: `transaction.authorized:transaction-uuid-123`

### Retry Logic

If your endpoint doesn't return a 2xx status code, TumiPay will automatically retry:

* **First retry**: 60 seconds (1 minute)
* **Second retry**: 600 seconds (10 minutes)
* **Third retry**: 1800 seconds (30 minutes)

<Tip>
  Return `200 OK` immediately upon receiving the webhook. Process the webhook asynchronously if needed, but don't wait for processing to complete before responding.
</Tip>

### Example Webhook Payload

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "event": "transaction.authorized",
  "timestamp": "2024-01-01T10:00:00.000Z",
  "idempotency_key": "transaction.authorized:transaction-uuid-123",
  "data": {
    "transaction": {
      "transaction_id": "transaction-uuid-123",
      "transaction_type": "PRE_AUTH_TRANSACTION",
      "transaction_status": "APPROVED",
      "amount": "100.00",
      "currency": "COP",
      "reference_id": "merchant-reference-123",
      "transaction_date": "2024-01-01T10:00:00Z"
    },
    "subscription": {
      "subscription_id": "subscription-uuid-456",
      "status": "ACTIVE"
    }
  }
}
```

### HTTP Headers

Every webhook request includes these headers:

| Header                | Description                            |
| --------------------- | -------------------------------------- |
| `X-Webhook-Event`     | Event type identifier                  |
| `X-Webhook-Timestamp` | ISO 8601 timestamp in UTC              |
| `X-Webhook-Id`        | Unique identifier for this webhook     |
| `X-Idempotency-Key`   | Key for duplicate detection            |
| `X-Webhook-Signature` | HMAC SHA256 signature for verification |
| `User-Agent`          | `TumiPay-Webhooks/1.0`                 |

### Complete Documentation

For detailed information about webhooks, including:

* Complete signature verification examples (PHP, Node.js, Python)
* All event payload structures
* Best practices and implementation guides
* Complete webhook handler examples

See the [complete Webhooks documentation](/api-reference/card-payment/webhooks).

***

## Support

For more information or to resolve questions about using Card Payment in Colombia, contact the support team:

* Email: [soporte@tumipay.co](mailto:soporte@tumipay.co)
* Technical email: [tecnologia@tumipay.co](mailto:tecnologia@tumipay.co)
