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

# Create Refund

> Create a full or partial refund for a completed collection. Specify amount, reason, and recipient. POST /refunds.

## Overview

Issue a full or partial refund for a completed collection. The refund amount is debited from your business wallet and credited to the payer's Fyatu account.

**Important**: Each collection can only be refunded once. Choose between a full refund or a partial refund at the time of processing.

## Path Parameters

| Parameter      | Type   | Description                 |
| -------------- | ------ | --------------------------- |
| `collectionId` | string | The collection ID to refund |

## Request Body

| Field    | Type   | Required    | Description                                                                              |
| -------- | ------ | ----------- | ---------------------------------------------------------------------------------------- |
| `mode`   | string | No          | Refund mode: `FULL` (default) or `PARTIAL`                                               |
| `amount` | number | Conditional | Required for `PARTIAL` mode. Refund amount in USD                                        |
| `reason` | string | No          | Reason code (default: `CUSTOMER_REQUEST`). See [available reasons](#refund-reason-codes) |

## Refund Modes

| Mode      | Description                                 | Amount Required |
| --------- | ------------------------------------------- | --------------- |
| `FULL`    | Refunds the entire net amount automatically | No              |
| `PARTIAL` | Refunds a specific amount you specify       | Yes             |

<Note>
  Use `FULL` mode to avoid calculation errors. The system automatically determines the maximum refundable amount (net amount after fees).
</Note>

## Refund Reason Codes

Use one of these predefined reason codes in the `reason` field:

| Code                       | Description                         |
| -------------------------- | ----------------------------------- |
| `DUPLICATE_PAYMENT`        | Duplicate payment                   |
| `FRAUDULENT`               | Fraudulent transaction              |
| `CUSTOMER_REQUEST`         | Customer requested refund (default) |
| `ORDER_CANCELLED`          | Order was cancelled                 |
| `PRODUCT_NOT_DELIVERED`    | Product/service not delivered       |
| `PRODUCT_NOT_AS_DESCRIBED` | Product/service not as described    |
| `PRICING_ERROR`            | Pricing or billing error            |
| `OTHER`                    | Other reason                        |

You can also retrieve these programmatically via `GET /api/v3/refunds/reasons`.

## Response

| Field                | Type   | Description                       |
| -------------------- | ------ | --------------------------------- |
| `refundId`           | string | Unique refund identifier          |
| `collectionId`       | string | Original collection ID            |
| `amount`             | number | Refunded amount                   |
| `currency`           | string | Currency code                     |
| `reason`             | string | Reason code                       |
| `reasonDescription`  | string | Human-readable reason description |
| `status`             | string | `COMPLETED`                       |
| `recipient`          | object | Payer who received the refund     |
| `recipient.clientId` | string | Payer's Fyatu client ID           |
| `recipient.name`     | string | Payer's name                      |
| `createdAt`          | string | Refund timestamp                  |

## Refund Rules

1. **Only Completed Collections**: Cannot refund pending, expired, or failed payments
2. **One Refund Per Collection**: Each collection can only be refunded once
3. **Maximum Refundable**: Net amount (original amount minus fees)
4. **Fees Non-Refundable**: Processing fees are retained
5. **Wallet Balance Required**: Your business wallet must have sufficient balance

## Example Usage

<CodeGroup>
  ```php PHP theme={null}
  <?php
  $collectionId = 'col_a1b2c3d4e5f6';

  // Full refund (recommended - automatically calculates amount)
  $response = file_get_contents(
      "https://api.fyatu.com/api/v3/collections/{$collectionId}/refund",
      false,
      stream_context_create([
          'http' => [
              'method' => 'POST',
              'header' => [
                  'Content-Type: application/json',
                  'Authorization: Bearer ' . $accessToken
              ],
              'content' => json_encode([
                  'mode' => 'FULL',
                  'reason' => 'CUSTOMER_REQUEST'
              ])
          ]
      ])
  );

  $result = json_decode($response, true);

  if ($result['success']) {
      echo "Refund successful: {$result['data']['refundId']}\n";
      echo "Amount refunded: \${$result['data']['amount']}\n";
      echo "Credited to: {$result['data']['recipient']['name']}\n";
  }

  // Partial refund example
  $partialResponse = file_get_contents(
      "https://api.fyatu.com/api/v3/collections/{$collectionId}/refund",
      false,
      stream_context_create([
          'http' => [
              'method' => 'POST',
              'header' => [
                  'Content-Type: application/json',
                  'Authorization: Bearer ' . $accessToken
              ],
              'content' => json_encode([
                  'mode' => 'PARTIAL',
                  'amount' => 10.00,
                  'reason' => 'PRODUCT_NOT_AS_DESCRIBED'
              ])
          ]
      ])
  );
  ```

  ```javascript Node.js theme={null}
  const collectionId = 'col_a1b2c3d4e5f6';

  // Full refund (recommended - automatically calculates amount)
  const response = await fetch(
    `https://api.fyatu.com/api/v3/collections/${collectionId}/refund`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${accessToken}`
      },
      body: JSON.stringify({
        mode: 'FULL',
        reason: 'CUSTOMER_REQUEST'
      })
    }
  );

  const result = await response.json();

  if (result.success) {
    console.log(`Refund successful: ${result.data.refundId}`);
    console.log(`Amount refunded: $${result.data.amount}`);
    console.log(`Credited to: ${result.data.recipient.name}`);
  }

  // Partial refund example
  const partialResponse = await fetch(
    `https://api.fyatu.com/api/v3/collections/${collectionId}/refund`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${accessToken}`
      },
      body: JSON.stringify({
        mode: 'PARTIAL',
        amount: 10.00,
        reason: 'PRODUCT_NOT_AS_DESCRIBED'
      })
    }
  );
  ```
</CodeGroup>

## Example Response (Full Refund)

```json theme={null}
{
  "success": true,
  "status": 201,
  "message": "Refund processed successfully",
  "data": {
    "refundId": "ref_a1b2c3d4e5f6",
    "collectionId": "col_a1b2c3d4e5f6",
    "amount": 25.00,
    "currency": "USD",
    "reason": "CUSTOMER_REQUEST",
    "reasonDescription": "Customer requested refund",
    "status": "COMPLETED",
    "recipient": {
      "clientId": "clt_a1b2c3d4e5f6",
      "name": "Alice Example"
    },
    "createdAt": "2026-01-08T14:00:00+00:00"
  },
  "meta": {
    "requestId": "req_refund123",
    "timestamp": "2026-01-08T14:00:00+00:00"
  }
}
```

## Example Response (Partial Refund)

```json theme={null}
{
  "success": true,
  "status": 201,
  "message": "Refund processed successfully",
  "data": {
    "refundId": "ref_b1c2d3e4f5a6",
    "collectionId": "col_a1b2c3d4e5f6",
    "amount": 10.00,
    "currency": "USD",
    "reason": "PRODUCT_NOT_AS_DESCRIBED",
    "reasonDescription": "Product/service not as described",
    "status": "COMPLETED",
    "recipient": {
      "clientId": "clt_a1b2c3d4e5f6",
      "name": "Alice Example"
    },
    "createdAt": "2026-01-08T14:00:00+00:00"
  },
  "meta": {
    "requestId": "req_refund124",
    "timestamp": "2026-01-08T14:00:00+00:00"
  }
}
```

## Amount Exceeds Maximum

If you request a partial refund amount that exceeds the maximum refundable, the API will return an error with the maximum amount:

```json theme={null}
{
  "success": false,
  "status": 400,
  "message": "Requested amount (50.00) exceeds maximum refundable amount",
  "error": {
    "code": "AMOUNT_EXCEEDS_REFUNDABLE",
    "maxRefundable": 24.25
  }
}
```

## Refund Amount Calculation

| Original Payment                | \$25.00     |
| ------------------------------- | ----------- |
| Processing Fee                  | -\$0.75     |
| **Net Amount (Max Refundable)** | **\$24.25** |

<Warning>
  Processing fees are non-refundable. The maximum refund amount is the net amount you received, not the original payment amount.
</Warning>

## Error Responses

| Error Code                  | HTTP | Description                                                       |
| --------------------------- | ---- | ----------------------------------------------------------------- |
| `RESOURCE_NOT_FOUND`        | 404  | Collection not found                                              |
| `INVALID_STATUS`            | 400  | Collection not in COMPLETED status                                |
| `AMOUNT_EXCEEDS_REFUNDABLE` | 400  | Requested amount exceeds maximum (includes `maxRefundable` value) |
| `ALREADY_REFUNDED`          | 400  | Collection has already been refunded                              |
| `INSUFFICIENT_BALANCE`      | 402  | Business wallet balance too low                                   |
| `PAYER_NOT_FOUND`           | 400  | Payer account no longer exists                                    |

## Collection Status After Refund

* **Full Refund**: Collection status changes to `REFUNDED`
* **Partial Refund**: Collection status changes to `PARTIALLY_REFUNDED`
* **Customer Notification**: Payer receives notification of the refund

<Tip>
  Keep track of refund IDs to handle customer inquiries and for accounting purposes.
</Tip>


## OpenAPI

````yaml v3/openapi.json POST /collections/{collectionId}/refund
openapi: 3.1.0
info:
  title: FYATU API v3
  description: >-
    FYATU API v3 with JWT authentication for Collections, Payouts, and Card
    Issuing.
  version: 3.0.0
  contact:
    name: FYATU Support
    url: https://fyatu.com
    email: support@fyatu.com
servers:
  - url: https://api.fyatu.com/api/v3
    description: Production
security: []
tags:
  - name: Authentication
    description: JWT token management endpoints
  - name: Account
    description: Business account, wallet, and address management
  - name: Collections
    description: Accept payments from customers via checkout sessions
  - name: Refunds
    description: Issue refunds for completed collections
  - name: Payouts
    description: Send money to Fyatu account holders
  - name: Cardholders
    description: Cardholder management for card issuing programs
  - name: Cards
    description: Issue, fund, freeze, and manage virtual cards
  - name: Webhooks
    description: Webhook configuration and management
paths:
  /collections/{collectionId}/refund:
    post:
      tags:
        - Refunds
      summary: Create Refund
      description: >-
        Issue a full or partial refund for a completed collection. Processing
        fees are non-refundable.
      operationId: createRefund
      parameters:
        - name: collectionId
          in: path
          required: true
          schema:
            type: string
          description: Collection ID or batch ID
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RefundRequest'
            example:
              mode: FULL
              reason: CUSTOMER_REQUEST
      responses:
        '201':
          description: Refund created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RefundResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          description: Insufficient balance
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          $ref: '#/components/responses/NotFound'
      security:
        - BearerAuth: []
components:
  schemas:
    RefundRequest:
      type: object
      properties:
        mode:
          type: string
          enum:
            - FULL
            - PARTIAL
          default: FULL
          description: 'Refund mode: FULL (auto-calculate) or PARTIAL (specify amount)'
        amount:
          type: number
          description: Refund amount (required for PARTIAL mode)
        reason:
          type: string
          enum:
            - DUPLICATE_PAYMENT
            - FRAUDULENT
            - CUSTOMER_REQUEST
            - ORDER_CANCELLED
            - PRODUCT_NOT_DELIVERED
            - PRODUCT_NOT_AS_DESCRIBED
            - PRICING_ERROR
            - OTHER
          default: CUSTOMER_REQUEST
          description: Reason code for refund
    RefundResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        status:
          type: integer
          example: 201
        message:
          type: string
        data:
          $ref: '#/components/schemas/RefundData'
        meta:
          $ref: '#/components/schemas/Meta'
    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        status:
          type: integer
          example: 401
        message:
          type: string
          example: Invalid credentials
        error:
          $ref: '#/components/schemas/Error'
        meta:
          $ref: '#/components/schemas/Meta'
    RefundData:
      type: object
      properties:
        refundId:
          type: string
        collectionId:
          type: string
        amount:
          type: number
        currency:
          type: string
        reason:
          type: string
          description: Reason code
        reasonDescription:
          type: string
          description: Human-readable reason
        status:
          type: string
          enum:
            - PENDING
            - COMPLETED
            - FAILED
        recipient:
          type: object
          properties:
            clientId:
              type: string
            name:
              type: string
        createdAt:
          type: string
          format: date-time
    Meta:
      type: object
      properties:
        requestId:
          type: string
          description: Unique request ID for tracking
          example: req_abc123def456
        timestamp:
          type: string
          format: date-time
          description: ISO 8601 timestamp of the response
    Error:
      type: object
      properties:
        code:
          type: string
          description: Error code for programmatic handling
          example: AUTH_INVALID_CREDENTIALS
        details:
          type: array
          items:
            $ref: '#/components/schemas/ValidationError'
          description: Validation error details (for VALIDATION_ERROR)
    ValidationError:
      type: object
      properties:
        field:
          type: string
          description: Field that failed validation
          example: appId
        message:
          type: string
          description: Validation error message
          example: AppId is required
  responses:
    ValidationError:
      description: Validation failed
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            status: 400
            message: Validation failed
            error:
              code: VALIDATION_ERROR
              details:
                - field: currency
                  message: Currency is required
            meta:
              requestId: req_abc123
              timestamp: '2026-01-05T10:30:00+00:00'
    Unauthorized:
      description: Authentication required or token invalid
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            status: 401
            message: Unable to identify business
            error:
              code: AUTH_TOKEN_INVALID
            meta:
              requestId: req_abc123
              timestamp: '2026-01-05T10:30:00+00:00'
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            status: 404
            message: Wallet not found
            error:
              code: RESOURCE_NOT_FOUND
            meta:
              requestId: req_abc123
              timestamp: '2026-01-05T10:30:00+00:00'
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: JWT access token obtained from /auth/token

````