## Documentation Index

Fetch the complete documentation index at: [/llms.txt](https://docs.withflex.com/llms.txt)

Use this file to discover all available pages before exploring further.

**Important IDs to store:**

- `checkout_session_id` \- Extract from redirect URL (e.g., `fcs_01kbjcmbt5mhsmaggfqc1a4rns`)
- This ID is required for creating refunds

You can also retrieve the checkout session to get additional details:

```http
GET /v1/checkout/sessions/{checkout_session_id}
```

Response includes:

- `payment_intent_id` \- Flex’s internal payment ID
- `latest_charge` \- Charge ID
- `status` \- Should be `complete` for refunds

---

## Primary Refund Endpoint

### POST /v1/checkout/sessions//refund

This is the **main refund endpoint** for processing refunds on completed checkout sessions.

**Base URL:** `https://api.withflex.com` (or your custom domain)

**Authentication:**

```http
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
```

---

## Request Format

### Option 1: Line Item-Based Refund (Granular Control)

Refund specific products/prices with custom amounts:

```json
{
  "checkout_session": {
    "line_items": [
      {
        "product": "fprod_01k3m6j3zqcvy6pbj1a65sszpw",
        "amount_to_refund": 2000
      },
      {
        "product": "fprod_01k3m6r0qj2bpc25q6h56r3jar",
        "amount_to_refund": 1500
      }
    ],
    "amount_tax": 350,
    "amount_shipping": 500,
    "amount_discount": 200,
    "refund_metadata": {
      "OrderNo": "ORDER123",
      "Source": "Customer_Request",
      "Reason": "Damaged_Product"
    }
  }
}
```

**Alternative: Use `price` instead of `product`**

```json
{
  "checkout_session": {
    "line_items": [
      {
        "price": "fprice_01k3m6j3zqcvy6pbj1a65sszpw",
        "amount_to_refund": 2000
      }
    ],
    "refund_metadata": {
      "reason": "customer_request"
    }
  }
}
```

---

### Option 2: Simple Amount-Based Refund

Refund a specific total amount without line item breakdown:

```json
{
  "checkout_session": {
    "amount": 5000,
    "refund_metadata": {
      "reason": "customer_not_satisfied",
      "order_id": "12345"
    }
  }
}
```

---

### Option 3: Full Refund

Refund the entire checkout session amount:

```json
{
  "checkout_session": {
    "refund_metadata": {
      "reason": "order_cancelled"
    }
  }
}
```

Or simply:

```json
{
  "checkout_session": {}
}
```

---

## Request Parameters

| Field                  | Type   | Required | Description                                    |
|------------------------|--------|----------|------------------------------------------------|
| `line_items`          | array  | No       | Specific line items to refund with amounts     |
| `line_items[].product`| string | One of   | Product ID to refund (e.g., `fprod_xxx`)      |
| `line_items[].price`  | string | product/price | Price ID to refund (e.g., `fprice_xxx`)      |
| `line_items[].amount_to_refund` | integer | No | Amount in cents for this item (omit for full item refund) |
| `amount`              | integer | No       | Total amount to refund in cents (alternative to line_items) |
| `amount_tax`          | integer | No       | Tax amount to refund in cents                  |
| `amount_shipping`      | integer | No       | Shipping amount to refund in cents             |
| `amount_discount`     | integer | No       | Discount amount to refund in cents             |
| `refund_metadata`     | object  | No       | Key-value pairs for tracking (order ID, reason, etc.) |

---

## Success Response

**Status Code:** `200 OK`

```json
{
  "checkout_session": {
    "checkout_session_id": "fcs_01kbjcmbt5mhsmaggfqc1a4rns",
    "status": "complete",
    "amount_total": 10000,
    "amount_subtotal": 9000,
    "currency": "usd",
    "customer": {
      "customer_id": "fcus_xxx",
      "email": "customer@example.com",
      "name": "John Doe"
    },
    "payment_intent": {
      "payment_intent_id": "fpi_xxx",
      "amount": 10000,
      "amount_received": 10000,
      "status": "succeeded"
    },
    "line_items": [...],
    "refunds": [
      {
        "refund_id": "fref_01kbjdxyz123",
        "payment_intent_id": "fpi_xxx",
        "amount": 3500,
        "status": "pending",
        "reason": null,
        "created_at": "2024-12-04T10:30:00Z",
        "test_mode": false,
        "metadata": {
          "OrderNo": "ORDER123",
          "Source": "Customer_Request"
        },
        "reference_id": null,
        "reference_type": "acquirer_reference_number",
        "reference_status": "pending",
        "items": [
          {
            "amount_refunded": 3500,
            "payment_intent": "fpi_xxx",
            "reference_id": null,
            "reference_type": "acquirer_reference_number",
            "reference_status": "pending"
          }
        ]
      }
    ]
  }
}
```

**Key Response Fields:**

- `refunds[].refund_id` \- Store this for tracking refund status
- `refunds[].status` \- Current refund status (`pending`, `succeeded`, `failed`)
- `refunds[].reference_id` \- Acquirer Reference Number (ARN) for bank tracking (populated later)
- `refunds[].reference_status` \- Status of reference number (`pending`, `available`, `unavailable`)

---

## Error Responses

### Checkout Session Not Complete (422 Unprocessable Entity)

```json
{
  "error": {
    "type": "validation_error",
    "message": "Checkout session must be complete",
    "errors": [
      {
        "loc": ["status"],
        "msg": "Checkout session must be complete",
        "type": "invalid_request_error"
      }
    ]
  }
}
```

**Cause:** Checkout session status is not `complete`

---

### Checkout Session Not Found (404 Not Found)

```json
{
  "error": {
    "type": "not_found",
    "message": "checkout session does not exist"
  }
}
```

**Cause:** Invalid `checkout_session_id` or doesn’t belong to your account

---

### Unauthorized (401 Unauthorized)

```json
{
  "error": {
    "type": "unauthorized",
    "message": "Invalid API key"
  }
}
```

**Cause:** Missing or invalid `Authorization` header

---

## Refund Statuses

| Status   | Description                                                |
|----------|------------------------------------------------------------|
| `pending` | Refund initiated, processing in progress                    |
| `requires_action` | Additional action required (rare)                       |
| `succeeded` | Refund completed, funds returned to customer              |
| `failed` | Refund failed (usually insufficient funds in connected account) |
| `canceled` | Refund was canceled                                      |

**Typical Timeline:**

- Refund status updates to `succeeded` within minutes to hours
- Funds appear in customer’s account within 5-10 business days (varies by bank)

---

## Complete Workflow Examples

### Example 1: Full Refund

**Step 1: Customer completes payment**  
You receive redirect after successful payment:

```
https://yoursite.com/success?session_id=fcs_01kbjcmbt5mhsmaggfqc1a4rns
```

**Step 2: Customer requests full refund**

```bash
curl -X POST https://api.withflex.com/v1/checkout/sessions/fcs_01kbjcmbt5mhsmaggfqc1a4rns/refund \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "checkout_session": {
      "refund_metadata": {
        "reason": "customer_cancelled_order",
        "order_id": "ORD-12345",
        "requested_by": "customer_service"
      }
    }
  }'
```

**Step 3: Response**

```json
{
  "checkout_session": {
    "checkout_session_id": "fcs_01kbjcmbt5mhsmaggfqc1a4rns",
    "status": "complete",
    "amount_total": 15000,
    "refunds": [
      {
        "refund_id": "fref_01kbjdxyz123",
        "amount": 15000,
        "status": "pending",
        "created_at": "2024-12-04T10:30:00Z",
        "metadata": {
          "reason": "customer_cancelled_order",
          "order_id": "ORD-12345"
        }
      }
    ]
  }
}
```

**Step 4: Track refund status (optional)**

```bash
curl -X GET https://api.withflex.com/v1/refunds/fref_01kbjdxyz123 \
  -H "Authorization: Bearer sk_live_xxx"
```

---

### Example 2: Partial Refund by Line Items

**Scenario:** Customer returns 1 of 3 items purchased  
**Request:**

```bash
curl -X POST https://api.withflex.com/v1/checkout/sessions/fcs_01kbjcmbt5mhsmaggfqc1a4rns/refund \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "checkout_session": {
      "line_items": [
        {
          "product": "fprod_yoga_mat",
          "amount_to_refund": 3500
        }
      ],
      "amount_tax": 280,
      "amount_shipping": 0,
      "refund_metadata": {
        "reason": "item_returned",
        "rma_number": "RMA-2024-1234",
        "returned_items": "Yoga Mat (Blue)"
      }
    }
  }'
```

**Explanation:**

- Refunding only the yoga mat: $35.00
- Including proportional tax: $2.80
- Not refunding shipping (customer kept other items)
- Total refund: $37.80

---

### Example 3: Partial Refund by Amount

**Scenario:** Price adjustment without item-level detail  
**Request:**

```bash
curl -X POST https://api.withflex.com/v1/checkout/sessions/fcs_01kbjcmbt5mhsmaggfqc1a4rns/refund \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "checkout_session": {
      "amount": 2000,
      "refund_metadata": {
        "reason": "price_match_guarantee",
        "original_amount": 15000,
        "adjusted_amount": 13000,
        "competitor": "CompetitorStore"
      }
    }
  }'
```

**Explanation:**

- Refunding $20.00 difference due to price match
- No line item breakdown needed
- Metadata tracks the reason

---

### Example 4: Multiple Partial Refunds

You can create multiple refunds for the same checkout session until the full amount is refunded.  
**First refund:** $50

```bash
curl -X POST https://api.withflex.com/v1/checkout/sessions/fcs_xxx/refund \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"checkout_session": {"amount": 5000}}'
```

**Second refund:** $30

```bash
curl -X POST https://api.withflex.com/v1/checkout/sessions/fcs_xxx/refund \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"checkout_session": {"amount": 3000}}'
```

**Important:** Track the total refunded amount to avoid over-refunding.

---

## Secondary Refund API

### Tracking and Listing Refunds

After creating a refund via the checkout session endpoint, use the secondary refund API to track status:

#### GET /v1/refunds/

```bash
curl -X GET https://api.withflex.com/v1/refunds/fref_01kbjdxyz123 \
  -H "Authorization: Bearer sk_live_xxx"
```

**Response:**

```json
{
  "refund": {
    "refund_id": "fref_01kbjdxyz123",
    "payment_intent_id": "fpi_xxx",
    "amount": 5000,
    "status": "succeeded",
    "reason": null,
    "created_at": "2024-12-04T10:30:00Z",
    "test_mode": false,
    "metadata": {
      "order_id": "12345"
    },
    "reference_id": "ARN8493274932",
    "reference_type": "acquirer_reference_number",
    "reference_status": "available",
    "items": [...]
  }
}
```

---

### GET /v1/refunds (List Refunds)

**Query Parameters:**

- `payment_intent` \- Filter by payment intent ID
- `checkout_session` \- Filter by checkout session ID
- `status` \- Filter by status

**Examples:**
```bash
# All refunds
curl -X GET https://api.withflex.com/v1/refunds \
  -H "Authorization: Bearer sk_live_xxx"

# Refunds for specific checkout session
curl -X GET https://api.withflex.com/v1/refunds?checkout_session=fcs_01kbjcmbt5mhsmaggfqc1a4rns \
  -H "Authorization: Bearer sk_live_xxx"

# Succeeded refunds only
curl -X GET https://api.withflex.com/v1/refunds?status=succeeded \
  -H "Authorization: Bearer sk_live_xxx"
```

**Response:**

```json
{
  "refunds": [
    {
      "refund_id": "fref_01kbjdxyz123",
      "payment_intent_id": "fpi_xxx",
      "amount": 5000,
      "status": "succeeded",
      "created_at": "2024-12-04T10:30:00Z",
      ...
    },
    {
      "refund_id": "fref_01kbjdabc456",
      "payment_intent_id": "fpi_yyy",
      "amount": 3000,
      "status": "pending",
      "created_at": "2024-12-03T15:20:00Z",
      ...
    }
  ]
}
```

---

#### PATCH /v1/refunds/ (Update Refund Metadata)

Update refund metadata or reason (does not change amount or status):

```bash
curl -X PATCH https://api.withflex.com/v1/refunds/fref_01kbjdxyz123 \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "refund": {
      "reason": "fraudulent",
      "metadata": {
        "updated_by": "admin",
        "investigation_id": "INV-2024-001"
      }
    }
  }'
```

---

## Testing

### Test Mode

Use test API keys (starting with `sk_test_`) to test refunds without affecting real money:

```bash
curl -X POST https://api.withflex.com/v1/checkout/sessions/fcs_test_xxx/refund \
  -H "Authorization: Bearer sk_test_xxx" \
  -H "Content-Type: application/json" \
  -d '{"checkout_session": {}}'
```

**Test Mode Behavior:**

- Refunds complete instantly with `status: "succeeded"`
- No actual money movement
- Reference IDs still generated for testing
- Full webhook flow works
