> This page is for version v1 (default).
> For other versions, use one of these documentation indexes:
> - v1 (default): https://developers.truemed.com/v-1/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developers.truemed.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developers.truemed.com/_mcp/server.

# Create Refund

POST https://dev-api.truemed.com/payments/v1/refund
Content-Type: application/json

Use this endpoint to refund payments Truemed has already processed on your behalf. Partial refunds are supported.

## Request Notes

The amount requested must be less than or equal to the total amount that the
payment was originally created with.

### Itemizing a refund

`amount` is what Truemed refunds. `item_details` tells Truemed how to attribute that amount across
the order's lines.

* Set each `item_details[].total` to the amount you are refunding for that line. It cannot exceed
  that item's `total_refundable` from
  [Get Payment Status](/api-reference/payment-sessions/retrieve-payment-session).
* Set `item_details[].quantity` to 0 to refund dollars without units. Use this for the rest of a line
  after an earlier partial refund already returned its units. The dollars stay on that line, and
  its eligibility determines how Truemed splits the refund across cards.
* Across all lines, the totals must not sum above `amount`.
* The totals may sum below `amount`. Truemed applies the remainder to the capture the refund targets.

### Multi-capture sessions

Each refund applies to one capture. Use the `capture_id` from the capture response, or `captures[].id`
from [Get Payment Status](/api-reference/payment-sessions/retrieve-payment-session).

* Pass `capture_id` when the session has more than one capture, or when any capture did not complete.
* You can refund a capture while the session is still `partially_captured`. Every capture has already
  charged the customer, so the refund returns that money and the uncaptured remainder stays held for
  later captures. While the session is `partially_captured`, pass `capture_id`. Truemed rejects the
  refund if another capture is still processing.
* To refund shipping or another amount with no line item, target the capture that charged it.
* To refund more than one capture, send one refund per capture.
* A refund never frees up authorization. Captures after a refund are still limited to the amount that
  was never captured.

### Order-level charges and discounts

`create_payment_session` accepts an `amount_details` object at the order level, carrying charges and
discounts that belong to the order rather than to any single line. Shipping and tax behave the same
way.

Because Truemed tracks `total_refundable` per item, an order-level amount appears in no item's
`total_refundable`. For a full refund, set `amount` to the full captured amount and each
`item_details[].total` to that item's `total_refundable`. The item totals then sum below `amount` by
the order-level amount, and Truemed applies that remainder to the capture the refund targets.

On a partial refund, `amount` sets how much of an order-level charge returns. To return none of it,
set `amount` equal to the sum of your item totals.

### How much returns to the HSA/FSA card

Truemed derives the eligible amount of a refund from the lines you itemize:

* When every itemized line qualifies for HSA/FSA spending, the whole `amount` counts as eligible.
* Otherwise Truemed pro-rates `amount` by the eligible ratio of the itemized lines.
* Eligible spending that the regular card paid returns there first. The remaining eligible amount
  returns to the HSA/FSA card, and the rest returns to the regular card.
* Truemed caps each card's share at its remaining refundable balance. If the regular card cannot
  cover its share, the shortfall returns to the HSA/FSA card within that card's refundable balance.

### Returning an amount that belongs to no item

Some refunds have no line behind them: a goodwill credit for a late delivery, or shipping returned on
its own. Omit `item_details` and send `amount` alone. An empty `item_details` list is the same request.

When a refund names no items, Truemed treats the refund as HSA/FSA-eligible first, up to the remaining
eligible amount. Eligible spending that the regular card paid returns there first. Truemed then uses
the HSA/FSA card's refundable balance and returns the rest to the regular card.
Name the lines in `item_details` to allocate the refund by those lines' eligible share.

Two caps apply either way, both measured against earlier refunds. `amount` cannot exceed what the
order still has left to return. The refund's eligible amount cannot exceed the eligible amount still
outstanding. Once no eligible amount remains, later refunds go to the regular card first, subject to
each card's refundable balance.

Itemizing is still worth doing when the refund does follow specific lines. It keeps each line's
remaining refundable amount accurate and puts the refund against that line on the customer's receipt.
Without it the refund is allocated correctly and capped the same way, but it appears as an
order-level adjustment and the individual lines keep their original refundable amounts.

## Response Notes

### Bad Request

HTTP Status: `400`

If a field is missing or the request is otherwise can't be processed, we'll return a `400`
with the following fields:

* `error` - can be one of:
  * `MissingField`: one of the required fields is not present in the request
  * `AmountInvalid`: the `amount` field is negative, 0, or greater than the amount remaining
    available to refund on the payment
  * `InvalidPaymentId`: requesting to refund a payment that does not exist
  * `ChargeDisputed`: Payment session has a pending dispute. Can't refund until the dispute is
    resolved. Lost disputes reduce the remaining refundable amount but no longer block refunds
    of the undisputed remainder.
  * `NoSessionCaptures`: The payment session can't be refunded because there haven't been any
    funds captured.
  * `ValidationError`: Truemed does not allow the refund in the session's current state. For example,
    `capture_id` is missing on a session with more than one capture, on a session with a capture that
    did not complete, or on a `partially_captured` session. Other causes: another capture or a void is
    still processing, or the session collected no funds.
* `message`:
  * Indication of one of the following:
    * Which field was missing
    * Details on how the amount was invalid
    * Invalid payment id

Reference: https://developers.truemed.com/api-reference/payment-sessions/create-refund

## Authentication

- `x-truemed-api-key` header (required) — Sales channel API key for merchant server-to-server authentication

## Servers

- `https://dev-api.truemed.com` (Development server, default)
- `https://api.truemed.com` (Production server)

## Request

### Body (application/json)

This endpoint expects a CreateRefundRequest.

- `amount` (integer, required) — The amount you wish to refund in cents. Cannot be greater than the total_amount originally charged.
- `idempotency_key` (string, required) — Allows the endpoint to be called multiple times, and must be unique to the refund request.
- `payment_id` (string, required) — The id returned to the partner by Truemed in response to a `create_payment_session` request.
- `reason` (enum, required) — Why you are initiating this refund request: customer_request - the customer requested a refund; fraudulent - the payment was fraudulent; duplicate_payment - the user checked out with HSA/FSA multiple times for one purchase. One of: - `customer_request` — The refund was requested by the customer. - `duplicate_payment` — The charge was a duplicate. - `fraudulent` — The charge was fraudulent; this feeds the fraud signal.
  - Allowed values: `customer_request`, `duplicate_payment`, `fraudulent`
- `capture_id` (string, optional, nullable) — The ID of the capture to refund, from `capture_id` in the capture response or `captures[].id` in the payment session status. Each refund applies to exactly one capture. Required when the session has more than one capture or is still `partially_captured`, and optional when a closed session has only one capture.
- `item_details` (list of RefundItemDetails, optional, nullable) — The items to refund. Truemed pro-rates `amount` by the eligible ratio of these lines to determine the refund's eligible amount. Eligible spending that the regular card paid returns there first. The remaining eligible amount returns to the HSA/FSA card, and the rest returns to the regular card. If the regular card cannot cover its share, the shortfall returns to the HSA/FSA card within its refundable balance. Omit this field, or send an empty list, and Truemed uses eligible-first allocation based on the remaining eligible amount and each card's refundable balance. That refund applies to the order rather than to any line, so each line's `total_refundable` and `quantity_refundable` stay unchanged. If the items sum below `amount`, Truemed applies the remainder to the capture the refund targets.

## Response

### 200

Successful response

- `refund_id` (string, required) — The unique ID for this refund. Multiple refunds can be associated with a single payment, in the case of partial refunds.

## Errors

### 400 Bad Request Error

Bad Request

- `error` (enum, required)
  - Allowed values: `TotalAmountInvalid`, `ValidationError`
- `message` (string, required)

### 404 Not Found Error

Not Found

- `error` (enum, required)
  - Allowed values: `NotFound`
- `message` (string, required)

### 405 Method Not Allowed Error

Method Not Allowed

- `error` (enum, required)
  - Allowed values: `MethodNotAllowed`
- `message` (string, required)

### 500 Internal Server Error

Internal Server Error

- `error` (enum, required)
  - Allowed values: `ServerError`
- `message` (string, required)

### 501 Not Implemented Error

Not Implemented

- `error` (enum, required)
  - Allowed values: `NotImplemented`
- `message` (string, required)

## Types

### RefundItemDetails

- `item_id` (string, required) — ID that uniquely identifies the item within the Payment; optionally specified when creating the payment and retrievable from payment session status or list payment sessions.
- `quantity` (integer, required) — The number of units of this item being refunded, up to `quantity_refundable` from payment session status or list payment sessions. Use 0 to refund dollars without units, for example the rest of a line after an earlier partial refund already returned its units.
- `total` (integer, required) — The amount in cents being refunded for this item, up to `total_refundable` from payment session status or list payment sessions. Across all items these totals must not sum above the refund's `amount`. They may sum below it, and Truemed applies the remainder to the capture the refund targets.

## Examples

**Request**

```json
{
  "amount": 1,
  "idempotency_key": "string",
  "payment_id": "string",
  "reason": "customer_request"
}
```

**Response**

```json
{
  "refund_id": "string"
}
```

**SDK Code**

```python
import requests

url = "https://dev-api.truemed.com/payments/v1/refund"

payload = {
    "amount": 1,
    "idempotency_key": "string",
    "payment_id": "string",
    "reason": "customer_request"
}
headers = {
    "x-truemed-api-key": "<apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://dev-api.truemed.com/payments/v1/refund';
const options = {
  method: 'POST',
  headers: {'x-truemed-api-key': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"amount":1,"idempotency_key":"string","payment_id":"string","reason":"customer_request"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```