Flex Refund API Guide - Flex Documentation
Documentation Index
Fetch the complete documentation index at: /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:
GET /v1/checkout/sessions/{checkout_session_id}
Response includes:
payment_intent_id- Flex’s internal payment IDlatest_charge- Charge IDstatus- Should becompletefor 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:
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:
{
"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
{
"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:
{
"checkout_session": {
"amount": 5000,
"refund_metadata": {
"reason": "customer_not_satisfied",
"order_id": "12345"
}
}
}
Option 3: Full Refund
Refund the entire checkout session amount:
{
"checkout_session": {
"refund_metadata": {
"reason": "order_cancelled"
}
}
}
Or simply:
{
"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
{
"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 statusrefunds[].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)
{
"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)
{
"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)
{
"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
succeededwithin 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
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
{
"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)
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:
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:
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
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
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/
curl -X GET https://api.withflex.com/v1/refunds/fref_01kbjdxyz123 \
-H "Authorization: Bearer sk_live_xxx"
Response:
{
"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 IDcheckout_session- Filter by checkout session IDstatus- Filter by status
Examples:
# 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:
{
"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):
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:
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