---
title: "Refund Transaction"
method: POST
path: "/orders/transactions/{id}/refund"
tags: ["Orders::Transaction"]
---

# Refund Transaction

`POST /orders/transactions/{id}/refund`

## Request

- Base URL: `https://myworkspace.myclickfunnels.com/api/v2`
- URL: `https://myworkspace.myclickfunnels.com/api/v2/orders/transactions/{id}/refund`
- Auth: one of:
  - HTTP bearer
  - OAuth 2
    - Authorization code: `https://accounts.myclickfunnels.com/oauth/authorize`
    - Token URL: `https://accounts.myclickfunnels.com/oauth/token`
- TypeScript: <https://skmtc.dev/myclickfunnels/apis/clickfunnels-api/docs/orders/transactions/:id/refund/post.ts> (a function with typed inputs; its response is checked against the schema)

Refund this charge, in full, through ClickFunnels' own refund path (the same path the in-app
refund button uses) so the money actually moves back through the payment processor (Payments
AI/Rebilly or Stripe).

A refund addresses a transaction because the transaction IS the charge: refundable balance and
refund eligibility are tracked per transaction, and the refund is recorded against this one. A
subscription order accumulates one charge per renewal and an invoice can carry more than one,
so neither identifies a single charge to reverse. List an order's charges with `GET
/orders/{order_id}/transactions` and refund the one you mean - a refundable charge has
`external_type` `sale` or `capture`, `result: approved`, and `status` `completed` or
`partially-refunded`.

Partial refunds are deliberately not offered here, so this always refunds the charge's full
outstanding amount. Writing `status: refunded` onto an invoice is not an alternative: that is
available only for external (self-managed) orders, and a local status write moves no money.

Payments AI/Rebilly records the refund synchronously, so the returned transaction already
reflects it (200). Stripe only initiates the refund and confirms it in a later webhook, so the
response is 202 and the returned transaction can still show its pre-refund `status`; poll `GET
/orders/transactions/{id}` for the settled state. Please refer to [our Orders Overview
guide](https://developers.myclickfunnels.com/docs/orders) for more information about the
different types of orders and payment processors.

## Path parameters

- `id` string, required

## Request body

- object
  - `orders_transaction` OrdersTransactionParametersRefund: Parameters for `POST /orders/transactions/{id}/refund`. Every field is optional - a bare POST (or `{"orders_transaction": {}}`) refunds the addressed charge with defaults. The refund is always for the charge's full outstanding amount, so there is no amount to send. Partial refunds are deliberately not offered here: they are a human-gated exception, handled in the ClickFunnels admin.
    - `reason` string: Defaults to `requested_by_customer`. Stripe orders accept only `duplicate`, `fraudulent`, or `requested_by_customer`; any other value returns 422 listing the accepted set. Payments AI (Rebilly) orders treat this as a free-text description that is recorded on the refund and the order timeline.
    - `partial` boolean: Must be `false` or omitted. Sending `true` returns 422 rather than silently refunding the full charge. An `amount` field is rejected the same way - honoring it would be a partial refund, and ignoring it would refund more than you asked for.

## Response `200`

OK - the processor refunded the charge in-request (Payments AI/Rebilly), so the returned transaction already reflects it. `status` becomes `refunded`, or `partially-refunded` when earlier refunds left a remaining balance.

- OrdersTransactionAttributes: Payments
  - `id` integer: Transaction ID
  - `public_id` string, nullable: Transaction public ID
  - `order_id` integer: Order ID
  - `status` string: Status
  - `external_type` string, nullable: Type
  - `external_id` string: External ID
  - `amount` string, nullable: Amount
  - `currency` string, nullable: Currency
  - `reason` string, nullable: Reason
  - `adjusted_transaction_id` string, nullable: Adjusted transaction
  - `result` string: Result
  - `billing_payment_instruction_id` string, nullable: Billing Payment Instruction ID
  - `billing_payment_instruction_type` string, nullable: Billing Payment Instruction Type
  - `arn` string, nullable: ARN
  - `is_rebill` boolean, nullable: Is Rebill
  - `rebill_number` string, nullable: Rebill Number
  - `created_at` string, nullable: Created
  - `updated_at` string, nullable: Updated

## Other responses

- `202`: Accepted - the processor accepted the refund but settles it asynchronously (Stripe). It confirms in a later webhook, so the returned transaction can still show its pre-refund `status`; poll `GET /orders/transactions/{id}` until it settles.
- `401`: Unauthorized
- `404`: Not Found - the transaction does not exist, does not belong to a workspace your API key can access, or is not a refundable charge (already refunded, declined, not a sale, on a deleted order, or a payment method that does not support API refunds). Both bodies below mean the same thing to a caller: not refundable. Which one you get depends on where the record was hidden, so match on the status rather than the message. Fetch `GET /orders/{order_id}/transactions` and check `external_type`, `result` and `status` to tell the cases apart.
- `422`: Unprocessable Entity - the request was understood but not performed. The charge keeps its previous status and no money moved, so it is safe to correct the request and retry.

## Changes

- **2026-11-03** `511d88b30aea`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/myclickfunnels/apis/clickfunnels-api/changes/orders/transactions/:id/refund/post.md)

---

[API](https://skmtc.dev/myclickfunnels/apis/clickfunnels-api.md) - [All operations](https://skmtc.dev/myclickfunnels/apis/clickfunnels-api/llms.txt) - [OpenAPI document](https://skmtc.dev/myclickfunnels/apis/clickfunnels-api/revisions/511d88b30aea?raw)
