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

# Chargeback Provider Integration

> Complete guide for chargeback providers to integrate with TagadaPay API for automatic refunds

This guide is designed for **chargeback and dispute management providers** who want to integrate with TagadaPay's API to provide automatic refund services to merchants. Learn how to use our API endpoints to fetch payments and process refunds with advanced options like dispute tracking and customer blacklisting.

***

## Overview

TagadaPay provides a comprehensive API that allows chargeback providers to:

* **Fetch payments** using flexible filtering options to match alerts with transactions
* **Process refunds** automatically with a single API call
* **Track disputes** by marking payments as disputed with detailed information
* **Blacklist customers** automatically to prevent future fraudulent transactions

### Key Benefits

* **Single API Call** — Process refunds, mark disputes, and blacklist customers in one request
* **Flexible Filtering** — Find payments by transaction ID, card details, customer info, and more
* **Comprehensive Tracking** — Automatically track dispute status, type, and reason codes
* **Fraud Prevention** — Automatically blacklist customers when processing refunds

***

## Getting Merchant API Keys

Before you can integrate with TagadaPay's API, merchants need to create and share their API access tokens with you.

### Merchant Responsibilities

Merchants are responsible for creating API keys in their TagadaPay account and providing them to you during the integration setup process.

<Steps>
  <Step title="Merchant Creates API Key">
    1. Log in to the TagadaPay dashboard at [app.tagadapay.com](https://app.tagadapay.com)
    2. Navigate to **Settings** → **API Keys**
    3. Click **Create API Key**
    4. Give the key a descriptive name (e.g., "Chargeback Provider Integration")
    5. Copy the generated API key
  </Step>

  <Step title="Merchant Shares API Key">
    Merchants should paste the API key into your provider's configuration page or integration setup form.

    <Info>
      Each merchant has their own unique API key that is scoped to their account data only. Never share API keys between merchants.
    </Info>
  </Step>

  <Step title="Provider Stores API Key Securely">
    Store the merchant's API key securely in your system. You'll use this key to authenticate all API requests on behalf of that merchant.
  </Step>
</Steps>

***

## Authentication

All API requests require Bearer token authentication using the merchant's API key:

```http theme={null}
Authorization: Bearer <merchant_api_key>
```

**Base URL:** `https://app.tagadapay.com`

<Warning>
  Always use HTTPS for all API requests. Never expose API keys in client-side code or public repositories.
</Warning>

***

## Endpoint 1: List Payments

Use this endpoint to search and filter payments to match chargeback alerts with transactions.

### Endpoint

```
POST /api/public/v1/payments
```

### Purpose

Fetch payments with flexible filtering options to:

* Match alerts by transaction ID, card details, or customer information
* Filter by payment status, date ranges, and dispute information
* Support pagination for large result sets

### Request Body

```json theme={null}
{
  "pagination": {
    "page": 1,
    "pageSize": 20
  },
  "sortBy": {
    "field": "createdAt",
    "direction": "desc"
  },
  "filters": {
    "storeIds": ["store_123"],
    "status": "succeeded",
    "currency": ["USD", "EUR"],
    "orderId": "ord_456",
    "isDisputed": false,
    "card": {
      "last4": "4242",
      "brand": "visa",
      "year": 2025,
      "month": 12
    },
    "customer": {
      "email": "customer@example.com",
      "fullName": "John Doe"
    },
    "date": {
      "condition": "is-between-date",
      "value": ["2024-01-01", "2024-12-31"]
    }
  }
}
```

### Filter Options

| Filter              | Type       | Description                                                                           |
| ------------------- | ---------- | ------------------------------------------------------------------------------------- |
| `storeIds`          | `string[]` | Filter by store IDs                                                                   |
| `status`            | `string`   | Payment status: `pending`, `succeeded`, `failed`, `refunded`, etc.                    |
| `subStatus`         | `string`   | Payment sub-status for more granular filtering                                        |
| `currency`          | `string[]` | Filter by currency codes (e.g., `["USD", "EUR"]`)                                     |
| `orderId`           | `string`   | Filter by specific order ID                                                           |
| `isDisputed`        | `boolean`  | Filter by dispute status                                                              |
| `disputeStatus`     | `string`   | Filter by dispute status: `response-needed`, `under-review`, `won`, `lost`, etc.      |
| `disputeType`       | `string`   | Filter by dispute type: `first-chargeback`, `ethoca-alert`, `rdr`, etc.               |
| `card.last4`        | `string`   | Filter by last 4 digits of card                                                       |
| `card.brand`        | `string`   | Filter by card brand: `visa`, `mastercard`, `amex`, etc.                              |
| `card.year`         | `number`   | Filter by card expiration year                                                        |
| `card.month`        | `number`   | Filter by card expiration month                                                       |
| `customer.email`    | `string`   | Filter by customer email                                                              |
| `customer.fullName` | `string`   | Filter by customer full name                                                          |
| `date.condition`    | `string`   | Date condition: `is-equal-date`, `is-between-date`, `is-after-date`, `is-before-date` |
| `date.value`        | `string[]` | Date values (ISO 8601 format)                                                         |

### Example Request

```bash theme={null}
curl -X POST https://app.tagadapay.com/api/public/v1/payments \
  -H "Authorization: Bearer sk_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "pagination": {
      "page": 1,
      "pageSize": 10
    },
    "filters": {
      "status": "succeeded",
      "card": {
        "last4": "4242"
      },
      "date": {
        "condition": "is-after-date",
        "value": ["2024-01-01"]
      }
    }
  }'
```

### Example Response

```json theme={null}
{
  "payments": [
    {
      "id": "pay_123xyz",
      "amount": 2999,
      "currency": "USD",
      "status": "succeeded",
      "subStatus": "approved",
      "createdAt": "2024-03-20T10:30:00Z",
      "orderId": "ord_456",
      "customer": {
        "id": "cus_789",
        "email": "customer@example.com",
        "firstName": "John",
        "lastName": "Doe"
      },
      "paymentInstrument": {
        "id": "pi_abc",
        "type": "card",
        "card": {
          "last4": "4242",
          "brand": "visa",
          "expYear": 2025,
          "expMonth": 12
        }
      },
      "transactions": [
        {
          "id": "txn_123",
          "type": "purchase",
          "status": "succeeded",
          "amount": 2999,
          "currency": "USD",
          "processorTransactionId": "pi_3ABC123XYZ"
        }
      ]
    }
  ],
  "total": 1,
  "pageCount": 1,
  "page": 1,
  "pageSize": 10
}
```

***

## Endpoint 2: Refund Payment

Use this endpoint to process refunds with advanced options for dispute tracking and customer blacklisting.

### Endpoint

```
POST /api/public/v1/payments/refund
```

### Purpose

Process full or partial refunds with optional features:

* **Mark as disputed** — Automatically track dispute information
* **Blacklist customer** — Prevent future transactions from the same customer
* **Cancel subscriptions** — Automatically cancel associated subscriptions

### Request Body

```json theme={null}
{
  "paymentIds": ["pay_123xyz"],
  "amount": 1500,
  "metadata": {
    "reason": "Chargeback alert - Ethoca",
    "initiatedBy": "chargeback_provider",
    "alertId": "ETH-2024-123456",
    "provider": "your-provider-name"
  },
  "cancelSubscription": false,
  "dispute": {
    "disputeStatus": "response-needed",
    "disputeType": "ethoca-alert",
    "disputeReasonCode": "fraudulent",
    "disputedTransactionId": "txn_123",
    "disputeNote": "Customer claims unauthorized transaction"
  },
  "blacklistCustomer": true
}
```

### Request Parameters

| Parameter            | Type       | Required | Description                                                               |
| -------------------- | ---------- | -------- | ------------------------------------------------------------------------- |
| `paymentIds`         | `string[]` | ✅ Yes    | Array of payment IDs to refund                                            |
| `amount`             | `number`   | ❌ No     | Partial refund amount (in minor units, e.g., cents). Omit for full refund |
| `metadata`           | `object`   | ❌ No     | Additional metadata to store with the refund                              |
| `cancelSubscription` | `boolean`  | ❌ No     | If `true`, cancels any associated subscription                            |
| `dispute`            | `object`   | ❌ No     | Dispute information (see Dispute Options below)                           |
| `blacklistCustomer`  | `boolean`  | ❌ No     | If `true`, automatically blacklists the customer                          |

### Dispute Options

When you include the `dispute` object, TagadaPay will automatically mark the payment as disputed with the provided information. This is especially useful for chargeback providers who want to track disputes in a single API call.

#### Dispute Object Structure

```json theme={null}
{
  "dispute": {
    "disputeStatus": "response-needed",
    "disputeType": "ethoca-alert",
    "disputeReasonCode": "fraudulent",
    "disputedTransactionId": "txn_123",
    "disputeNote": "Additional notes about the dispute"
  }
}
```

#### Dispute Status Values

| Value                 | Description                   |
| --------------------- | ----------------------------- |
| `response-needed`     | Merchant response required    |
| `under-review`        | Currently being reviewed      |
| `forfeited`           | Dispute forfeited             |
| `won`                 | Dispute won by merchant       |
| `lost`                | Dispute lost by merchant      |
| `unknown`             | Status unknown                |
| `refunded`            | Dispute resolved with refund  |
| `refunded_externally` | Refunded outside of TagadaPay |

#### Dispute Type Values

| Value                 | Description                           |
| --------------------- | ------------------------------------- |
| `information-request` | Information request from card network |
| `first-chargeback`    | First chargeback                      |
| `second-chargeback`   | Second chargeback                     |
| `arbitration`         | Arbitration case                      |
| `fraud`               | Fraud dispute                         |
| `ethoca-alert`        | Ethoca alert notification             |
| `verifi-alert`        | Verifi alert notification             |
| `bank-return`         | Bank return                           |
| `paypal-claim`        | PayPal claim                          |
| `representment`       | Representment case                    |
| `rdr`                 | Rapid Dispute Resolution              |

#### Dispute Reason Codes

Common reason codes include: `fraudulent`, `unrecognized`, `duplicate`, `subscription_canceled`, `product_unacceptable`, `credit_not_processed`, `general`, and more.

### Blacklist Customer Option

When `blacklistCustomer` is set to `true`, TagadaPay will automatically create a block rule that prevents future transactions from:

* The same customer ID
* The same email address

This is particularly useful for chargeback providers who want to prevent repeat fraudsters from making additional purchases.

<Info>
  The blacklist is permanent by default and will block all future transactions from the blacklisted customer or email address.
</Info>

### Example: Full Refund with Dispute Tracking

```bash theme={null}
curl -X POST https://app.tagadapay.com/api/public/v1/payments/refund \
  -H "Authorization: Bearer sk_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "paymentIds": ["pay_123xyz"],
    "metadata": {
      "reason": "Ethoca alert - Fraudulent transaction",
      "alertId": "ETH-2024-123456",
      "provider": "your-provider-name"
    },
    "dispute": {
      "disputeStatus": "response-needed",
      "disputeType": "ethoca-alert",
      "disputeReasonCode": "fraudulent",
      "disputeNote": "Customer claims unauthorized transaction"
    },
    "blacklistCustomer": true
  }'
```

### Example: Partial Refund with Subscription Cancellation

```bash theme={null}
curl -X POST https://app.tagadapay.com/api/public/v1/payments/refund \
  -H "Authorization: Bearer sk_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "paymentIds": ["pay_123xyz"],
    "amount": 1500,
    "cancelSubscription": true,
    "metadata": {
      "reason": "Partial refund - Customer request"
    }
  }'
```

### Example Response

```json theme={null}
[
  {
    "id": "pay_123xyz",
    "amount": 2999,
    "refundedAmount": 1500,
    "currency": "USD",
    "status": "partially_refunded",
    "isDisputed": true,
    "disputeStatus": "response-needed",
    "disputeType": "ethoca-alert",
    "disputeReasonCode": "fraudulent",
    "refund": {
      "id": "ref_456",
      "amount": 1500,
      "currency": "USD",
      "status": "succeeded",
      "createdAt": "2024-03-20T10:30:00Z"
    }
  }
]
```

***

## Complete Integration Example

Here's a complete example showing how to handle a chargeback alert:

```javascript theme={null}
const axios = require('axios');

const BASE_URL = 'https://app.tagadapay.com';
const MERCHANT_API_KEY = 'sk_live_abc123...';

async function handleChargebackAlert(alert, merchantApiKey) {
  // Step 1: Search for the payment
  const searchResponse = await axios.post(
    `${BASE_URL}/api/public/v1/payments`,
    {
      pagination: { page: 1, pageSize: 10 },
      filters: {
        status: 'succeeded',
        // Match by processor transaction ID if available
        // Or use card details, customer email, etc.
      },
    },
    {
      headers: {
        Authorization: `Bearer ${merchantApiKey}`,
        'Content-Type': 'application/json',
      },
    }
  );

  if (!searchResponse.data.payments || searchResponse.data.payments.length === 0) {
    console.log('No matching payment found');
    return { matched: false };
  }

  // Find the matching payment (you may need custom matching logic)
  const payment = findMatchingPayment(searchResponse.data.payments, alert);

  if (!payment) {
    console.log('No matching payment found after filtering');
    return { matched: false };
  }

  // Step 2: Process refund with dispute tracking and blacklisting
  const refundResponse = await axios.post(
    `${BASE_URL}/api/public/v1/payments/refund`,
    {
      paymentIds: [payment.id],
      metadata: {
        reason: `Chargeback alert - ${alert.network}`,
        alertId: alert.id,
        provider: 'your-provider-name',
        receivedAt: alert.receivedAt,
      },
      dispute: {
        disputeStatus: 'response-needed',
        disputeType: alert.type === 'ethoca' ? 'ethoca-alert' : 'verifi-alert',
        disputeReasonCode: alert.reasonCode || 'fraudulent',
        disputeNote: alert.description || 'Chargeback alert received',
      },
      blacklistCustomer: true, // Automatically blacklist the customer
    },
    {
      headers: {
        Authorization: `Bearer ${merchantApiKey}`,
        'Content-Type': 'application/json',
      },
    }
  );

  if (refundResponse.status === 200) {
    console.log('Refund successful:', refundResponse.data);
    return {
      matched: true,
      refunded: true,
      paymentId: payment.id,
      refundId: refundResponse.data[0]?.refund?.id,
    };
  } else {
    console.error('Refund failed:', refundResponse.data);
    return {
      matched: true,
      refunded: false,
      error: refundResponse.data,
    };
  }
}

// Helper function to match alerts with payments
function findMatchingPayment(payments, alert) {
  return payments.find((payment) => {
    // Match by processor transaction ID
    if (alert.processorTransactionId) {
      return payment.transactions.some(
        (txn) => txn.processorTransactionId === alert.processorTransactionId
      );
    }
    
    // Match by card last4 and amount
    if (alert.cardLast4 && alert.amount) {
      return (
        payment.paymentInstrument?.card?.last4 === alert.cardLast4 &&
        payment.amount === alert.amount
      );
    }
    
    // Match by customer email and amount
    if (alert.customerEmail && alert.amount) {
      return (
        payment.customer?.email === alert.customerEmail &&
        payment.amount === alert.amount
      );
    }
    
    return false;
  });
}

// Usage
const alert = {
  id: 'ETH-2024-123456',
  network: 'ethoca',
  type: 'ethoca',
  processorTransactionId: 'pi_3ABC123XYZ',
  amount: 2999,
  reasonCode: 'fraudulent',
  description: 'Customer claims unauthorized transaction',
  receivedAt: '2024-03-20T10:15:00Z',
};

handleChargebackAlert(alert, MERCHANT_API_KEY);
```

***

## Best Practices

### ✅ Do

* **Always search first** — Use the list payments endpoint to find the correct payment before refunding
* **Include dispute information** — Use the `dispute` option to track disputes automatically
* **Use blacklist for fraud** — Enable `blacklistCustomer` for fraudulent transactions
* **Store metadata** — Include relevant alert information in the `metadata` field
* **Handle errors gracefully** — Check for payment not found, already refunded, etc.
* **Use idempotent requests** — Include unique alert IDs in metadata to prevent duplicate refunds

### ❌ Don't

* **Skip payment matching** — Always verify you're refunding the correct payment
* **Forget dispute tracking** — Use the `dispute` option to maintain accurate records
* **Expose API keys** — Never log or expose merchant API keys
* **Refund without verification** — Always match alerts with payments before processing
* **Ignore error responses** — Handle API errors appropriately

***

## Error Handling

### Common Error Scenarios

| Error              | Description                | Solution                                                 |
| ------------------ | -------------------------- | -------------------------------------------------------- |
| `401 Unauthorized` | Invalid or missing API key | Verify the merchant's API key is correct                 |
| `404 Not Found`    | Payment not found          | Verify the payment ID exists and belongs to the merchant |
| `400 Bad Request`  | Invalid request parameters | Check request body format and required fields            |
| `409 Conflict`     | Payment already refunded   | Check payment status before attempting refund            |

### Error Response Format

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

***

## Support

If you have questions or need assistance with the integration:

* **Email:** [api-support@tagadapay.com](mailto:api-support@tagadapay.com)
* **Documentation:** [TagadaPay API Reference](/api-reference/introduction)

***

## Related Documentation

* [Chargeback Management Overview](https://help.tagada.io/chargebacks)
* [Payment API Reference](/api-reference/introduction)
