DGuardAPI Docs

Fraud Refund

The Fraud Refund module allows you to manage automatic refunds to customers affected by fraudulent transactions. DGuard processes refunds instantly directly to the customer's account.

Available Endpoints

POST/refund/request
GET/refund/{refund_id}
GET/refund/list
POST/refund/{refund_id}/cancel
POST/refund/{refund_id}/void
POST/refund/{refund_id}/retry

Features

Instant Refunds

Less than 30 seconds

Direct Integration

With local payment systems

Complete Traceability

Full process tracking

Idempotent Requests

Safe retry with idempotency keys

Idempotency

All refund requests must include an idempotency key to prevent duplicate refunds. This is critical for ensuring safe retries in case of network failures or timeouts.

Idempotency Key Requirements

  • - Include the key in the Idempotency-Key header
  • - Use a unique value per refund attempt (e.g., UUID v4)
  • - Keys are valid for 24 hours after first use
  • - Reusing a key within 24h returns the original response (no duplicate refund)
  • - After 24h, the same key cannot be reused for a new request

Header Example

bash
curl -X POST https://api.dguard.ai/v1/refund/request \
  -H "Authorization: Bearer {access_token}" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -H "Content-Type: application/json" \
  -d '{ ... }'

Refund States

Refunds progress through the following states. Subscribe to webhooks to receive real-time notifications on state changes.

pending

Request received and validated, awaiting processing

Initial state after successful request submission. Typically transitions to 'processing' within 1-2 seconds.

processing

Transfer in progress with payment network

Funds are being transferred. This state usually lasts 5-30 seconds depending on the payment network.

completed

Refund completed successfully

Funds have been credited to the beneficiary's account. This is a terminal state.

failed

Refund failed during processing

The payment network rejected the transfer. Check the 'failure_reason' field. Can be retried via POST /refund/{id}/retry.

cancelled

Cancelled before processing completed

Refund was cancelled via POST /refund/{id}/cancel while still in 'pending' state. Cannot cancel once 'processing' begins.

voided

Administratively voided after review

See 'Voided State' section below for detailed explanation.

State Transition Flow

pendingprocessingcompleted
From pending:cancelledFrom processing:failed(retry)pending
Admin action (any non-terminal state):voided

Understanding the Voided State

The voided state is a special administrative state that can only be set by DGuard operations team or via the admin-only POST /refund/{refund_id}/void endpoint.

When a Refund is Voided

Fraud Not Confirmed

Investigation determined the original transaction was legitimate, not fraudulent. The refund should not have been issued.

Beneficiary Data Error

Account details provided were incorrect or belong to a different party. The refund cannot be processed to the intended recipient.

Duplicate Refund Detected

A refund for the same transaction was already processed through another channel or system.

Compliance Hold

Regulatory or compliance review flagged the refund for potential money laundering or sanctions concerns.

Customer Request

The customer explicitly requested to void the refund (e.g., dispute resolved with merchant directly).

Voided vs Cancelled

Cancelled: Client-initiated action before processing completes. Funds were never transferred.
Voided: Administrative action that may occur even after funds were transferred. If funds were already sent, a reversal process may be initiated separately.

Voided Refund Response Example

json
{
  "refund_id": "ref_abc123xyz",
  "status": "voided",
  "voided_at": "2025-01-15T10:30:00Z",
  "voided_by": "admin@dguard.ai",
  "void_reason": "fraud_not_confirmed",
  "void_details": "Investigation concluded transaction was authorized by account holder.",
  "original_amount": 5234.00,
  "funds_transferred": true,
  "reversal_status": "pending",
  "reversal_reference": "REV-20250115-001234"
}

Request Refund

POST/refund/request

Create a new refund request for a fraudulent transaction. Requires a valid Idempotency-Key header.

Request Example

json
// Headers:
// Authorization: Bearer {access_token}
// Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
// Content-Type: application/json

{
  "transaction_id": "txn_abc123",
  "alert_id": "alert_xyz789",
  "refund": {
    "amount": 5234.00,
    "currency": "EUR",
    "reason": "confirmed_fraud",
    "description": "Unauthorized transaction reported by client"
  },
  "beneficiary": {
    "user_id": "usr_123456",
    "account_id": "acc_789012",
    "name": "Juan García López",
    "account_number": "JO94CBJO0010000000000131000302",
    "bank_code": "UBSIJOAXXXX"
  },
  "metadata": {
    "case_id": "CASE-2025-001234",
    "agent_id": "agent_jane_doe"
  }
}

Response Example (201 Created)

json
{
  "refund_id": "ref_abc123xyz",
  "status": "pending",
  "idempotency_key": "550e8400-e29b-41d4-a716-446655440000",
  "transaction_id": "txn_abc123",
  "amount": 5234.00,
  "currency": "EUR",
  "beneficiary": {
    "name": "Juan García López",
    "account_masked": "JO94****0302"
  },
  "created_at": "2025-01-14T17:30:00Z",
  "estimated_completion": "2025-01-14T17:31:00Z",
  "tracking": {
    "reference": "DGUARD-REF-20250114-001234",
    "trace_id": "trc_xyz789"
  }
}

Idempotency Behavior

If you send a request with the same Idempotency-Key within 24 hours:

  • - If the original request succeeded: Returns 200 OK with the original refund data
  • - If the original request is still processing: Returns 409 Conflict
  • - If the original request failed: Returns 400 Conflict with the failure details

Check Refund Status

GET/refund/{refund_id}

Completed Response (200 OK)

json
{
  "refund_id": "ref_abc123xyz",
  "status": "completed",
  "idempotency_key": "550e8400-e29b-41d4-a716-446655440000",
  "transaction_id": "txn_abc123",
  "amount": 5234.00,
  "currency": "EUR",
  "beneficiary": {
    "name": "Juan García López",
    "account_masked": "JO94****0302"
  },
  "created_at": "2025-01-14T17:30:00Z",
  "completion": {
    "completed_at": "2025-01-14T17:30:18Z",
    "reference": "CLIQ-20250114-789012",
    "processing_time_seconds": 18
  },
  "metadata": {
    "case_id": "CASE-2025-001234",
    "agent_id": "agent_jane_doe"
  }
}

List Refunds

GET/refund/list

Retrieve a paginated list of refunds with optional filtering by status, date range, and user.

Query Parameters

statusstringFilter by status (pending, processing, completed, failed, cancelled, voided)
user_idstringFilter by user ID
date_fromISO 8601Start date for filtering
date_toISO 8601End date for filtering
pageintegerPage number (default: 1)
page_sizeintegerResults per page (default: 50, max: 100)

Response Example (200 OK)

json
{
  "data": [
    {
      "refund_id": "ref_abc123xyz",
      "status": "completed",
      "amount": 5234.00,
      "currency": "EUR",
      "created_at": "2025-01-14T17:30:00Z"
    },
    {
      "refund_id": "ref_def456xyz",
      "status": "pending",
      "amount": 150.00,
      "currency": "EUR",
      "created_at": "2025-01-14T18:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "page_size": 50,
    "total_items": 127,
    "total_pages": 3
  }
}

Cancel Refund

POST/refund/{refund_id}/cancel

Cancel a refund that is still in pending status. Refunds that have already started processing cannot be cancelled.

Request Example

json
{
  "reason": "Customer resolved dispute with merchant directly",
  "cancelled_by": "agent_jane_doe"
}

Response Example (200 OK)

json
{
  "refund_id": "ref_abc123xyz",
  "status": "cancelled",
  "cancelled_at": "2025-01-14T17:30:05Z",
  "cancelled_by": "agent_jane_doe",
  "cancel_reason": "Customer resolved dispute with merchant directly"
}

Attempting to cancel a refund that is not in pending status will return error code REFUND_006 (Invalid state transition).

Retry Failed Refund

POST/refund/{refund_id}/retry

Retry a refund that has failed status. You can optionally update the beneficiary details if the failure was due to incorrect account information.

Request Example (with updated beneficiary)

json
{
  "update_beneficiary": {
    "account_number": "JO94CBJO0010000000000131000999",
    "bank_code": "UBSIJOAXXXX"
  },
  "retry_reason": "Corrected account number per customer"
}

Response Example (200 OK)

json
{
  "refund_id": "ref_abc123xyz",
  "status": "pending",
  "retry_count": 2,
  "previous_failure": {
    "failed_at": "2025-01-14T17:30:10Z",
    "failure_reason": "INVALID_ACCOUNT_NUMBER"
  },
  "created_at": "2025-01-14T17:30:00Z",
  "retried_at": "2025-01-14T18:00:00Z"
}

Refund Reasons

confirmed_fraudFraud confirmed by client
unauthorized_transactionUnauthorized transaction
account_takeoverCompromised account
card_stolenStolen card
phishing_victimPhishing victim
otherOther reason (specify in description)

Rate Limiting

Rate limits for the Fraud Refund module are enforced per application. All endpoints share the same quota based on your plan. For detailed specifications, see the Security & Compliance page.

Sandbox: 60 req/min
Production: 1,000 req/min