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

# Crear un reembolso

POST https://app.recurrente.com/api/refunds
Content-Type: application/json

Reembolsa un intent. Usa `intent_id` con el ID unificado `in_…` para
cualquier tipo compatible. `payment_intent_id` sigue aceptándose como
alias legado para integraciones existentes.

Para pagos electrónicos, devuelve los fondos al método de pago original
del cliente. Para un pago con Balance Recurrente (`balance`), el monto
completo regresa al instante al balance del pagador. Para una venta en
efectivo (`cash`), registra la devolución que realiza el comercio por
fuera de Recurrente, sin mover dinero. El intent solo se cancela cuando
los reembolsos acumulados cubren el total.
Envía `amount_in_cents` para solicitar un reembolso parcial en CyberSource,
Visa CyberSource o efectivo (`cash`). Si omites el monto, se reembolsa todo el saldo
pendiente. Puedes enviar varios reembolsos parciales hasta cubrir el total.
Otros proveedores solo admiten el saldo pendiente completo.

Si la venta tiene una factura certificada por Recurrente, cada parcial
genera una nota de crédito por el monto correspondiente y conserva la
factura original. Un reembolso del total original intenta anularla primero;
usa nota de crédito si el período cerró o la factura ya tiene una nota.
Esto aplica también a `cash_sales`. Un refund exitoso no garantiza que
la corrección fiscal haya terminado: puede fallar o requerir reintentos.
Las facturas emitidas fuera de Recurrente las corrige el comercio.

Para reembolsar un cobro de una cuenta conectada, envía su ID en el
header `X-ACCOUNT-ID`; la API key debe permitir movimientos de dinero.
Envía `refund_application_fee: true` para regresar a la cuenta dueña del
cobro todas sus comisiones de plataforma antes de solicitar el reembolso
al procesador. El valor predeterminado es `false` y las distribuciones
con `purpose: fund_split` nunca se revierten por este parámetro.

Recurrente reserva los movimientos y el balance del comercio sin
mantener bloqueos durante la llamada externa. Si el procesador rechaza
el reembolso, crea movimientos compensatorios. Una factura fiscal de
comisión se puede anular cuando todas sus líneas pertenecen a este
reembolso; un documento que agrupa otros pagos hace fallar la solicitud
antes de contactar al procesador. Si otra solicitud ya está procesando
el mismo reembolso, responde `202` y no vuelve a llamar al proveedor.
Si el resultado del proveedor queda indeterminado, el reembolso permanece
`pending` con `failure_reason: provider_outcome_unknown`; Recurrente conserva
la reserva, no reintenta automáticamente y un POST posterior responde `422`
con el `refund_id` para consultar y reconciliar el caso.

Usa un `Idempotency-Key` único por reembolso. Cuando una solicitud parcial
responde `202`, las repeticiones con la misma llave y cuerpo reproducen
esa respuesta con el mismo `refund_id`; consulta ese ID antes de enviar
otro monto.


Reference: https://docs.recurrente.com/referencia-api/api-reference/refunds/create-refund

## Authentication

- `X-SECRET-KEY` header (required) — Tu clave secreta de API. Una llave de cuenta (`sk_live_...`, `sk_test_...`) opera sobre su propia cuenta y, con `X-ACCOUNT-ID`, sobre sus cuentas conectadas. La llave también fija el ambiente: una `sk_test_` solo lista y resuelve objetos de prueba (`live_mode: false`) y una `sk_live_` solo objetos reales. Un ID del otro ambiente responde `404` (`401` en `/customers`). Una llave de organización (`sk_org_live_...`, `sk_org_test_...`) alcanza todas las cuentas de una organización y solo sirve para leer: saldos, movimientos y reportes. Para operar sobre una cuenta debe nombrarla con `X-ACCOUNT-ID`; omitirlo en una lectura devuelve todas las cuentas de la organización. Cualquier otro endpoint responde `403` con `code: organization_key_unsupported`.

## Request

### Body (application/json)

This endpoint expects a Refunds_createRefund_Request.

- `Refunds_createRefund_Request`

## Response

### 200

Reembolso procesado

- `id` (string, optional) — ID del reembolso
- `status` (enum, optional) — Estado del reembolso
  - Allowed values: `pending`, `succeeded`, `failed`, `voided`
- `failure_reason` (string, optional, nullable) — Razón del fallo. `provider_outcome_unknown` indica que el resultado debe reconciliarse antes de reintentar
- `customer` (RefundCustomer, optional)
- `user_id` (string, optional) — ID del usuario
- `account_id` (string, optional) — Cuenta dueña del cobro reembolsado
- `account_refunded_amount_in_cents` (integer, optional) — Monto debitado de la cuenta del comercio (en centavos)
- `customer_refunded_amount_in_cents` (integer, optional) — Monto devuelto al cliente (en centavos)
- `refund_application_fee` (boolean, optional) — Si las comisiones de plataforma se devolvieron con el reembolso
- `transfer_adjustments` (list of RefundTransferAdjustment, optional) — Transfer setups cancelados o revertidos por este reembolso
- `currency` (string, optional) — Moneda
- `created_at` (datetime, optional) — Fecha de creación
- `voided_at` (datetime, optional, nullable) — Fecha de anulación, si el reembolso fue anulado

### 202

El mismo reembolso ya se está procesando

- `id` (string, optional) — ID del reembolso
- `status` (enum, optional) — Estado del reembolso
  - Allowed values: `pending`, `succeeded`, `failed`, `voided`
- `failure_reason` (string, optional, nullable) — Razón del fallo. `provider_outcome_unknown` indica que el resultado debe reconciliarse antes de reintentar
- `customer` (RefundCustomer, optional)
- `user_id` (string, optional) — ID del usuario
- `account_id` (string, optional) — Cuenta dueña del cobro reembolsado
- `account_refunded_amount_in_cents` (integer, optional) — Monto debitado de la cuenta del comercio (en centavos)
- `customer_refunded_amount_in_cents` (integer, optional) — Monto devuelto al cliente (en centavos)
- `refund_application_fee` (boolean, optional) — Si las comisiones de plataforma se devolvieron con el reembolso
- `transfer_adjustments` (list of RefundTransferAdjustment, optional) — Transfer setups cancelados o revertidos por este reembolso
- `currency` (string, optional) — Moneda
- `created_at` (datetime, optional) — Fecha de creación
- `voided_at` (datetime, optional, nullable) — Fecha de anulación, si el reembolso fue anulado

## Errors

### 422 Unprocessable Entity Error

No se pudo procesar el reembolso

- `message` (string, optional) — Mensaje de error
- `code` (string, optional) — Código estable legible por máquinas, cuando aplica
- `refund_id` (string, optional) — ID del reembolso relacionado cuando aplica
- `endpoint` (string, optional) — Acción de API rechazada, cuando aplica
- `errors` (ErrorErrors, optional) — Detalles de errores por campo

## Types

### RefundCustomer

- `id` (string, optional) — ID del cliente
- `email` (string, optional)
- `full_name` (string, optional)

### RefundTransferAdjustment

- `action` (enum, required)
  - Allowed values: `cancel`, `reverse`
- `transfer_setup_id` (string, required) — Transfer setup afectado
- `amount_in_cents` (integer, required)
- `reversal_transfer_id` (string, optional, nullable) — Transfer inverso creado; `null` cuando solo se canceló un setup pendiente
- `restoration_transfer_id` (string, optional, nullable) — Transfer compensatorio creado si el procesador rechazó el reembolso
- `restored_at` (datetime, optional, nullable) — Momento en que el ajuste se compensó por un rechazo del procesador

### ErrorErrors

Detalles de errores por campo

## Examples

### Example 1

**Request**

```json
null
```

**Response**

```json
{
  "id": "re_3jfrywsf",
  "status": "succeeded",
  "failure_reason": "string",
  "customer": {
    "id": "string",
    "email": "string",
    "full_name": "string"
  },
  "user_id": "string",
  "account_id": "ac_restaurant",
  "account_refunded_amount_in_cents": 2187,
  "customer_refunded_amount_in_cents": 2500,
  "refund_application_fee": true,
  "transfer_adjustments": [
    {
      "action": "cancel",
      "transfer_setup_id": "string",
      "amount_in_cents": 1,
      "reversal_transfer_id": "string",
      "restoration_transfer_id": "string",
      "restored_at": "2024-01-15T09:30:00Z"
    }
  ],
  "currency": "GTQ",
  "created_at": "2024-01-15T09:30:00Z",
  "voided_at": "2024-01-15T09:30:00Z"
}
```

**SDK Code**

```python
import requests

url = "https://app.recurrente.com/api/refunds"

headers = {
    "X-SECRET-KEY": "<apiKey>",
    "Content-Type": "application/json"
}

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

print(response.json())
```

```javascript
const url = 'https://app.recurrente.com/api/refunds';
const options = {
  method: 'POST',
  headers: {'X-SECRET-KEY': '<apiKey>', 'Content-Type': 'application/json'},
  body: 'null'
};

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

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://app.recurrente.com/api/refunds"

	payload := strings.NewReader("null")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("X-SECRET-KEY", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://app.recurrente.com/api/refunds")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["X-SECRET-KEY"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "null"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://app.recurrente.com/api/refunds")
  .header("X-SECRET-KEY", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("null")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://app.recurrente.com/api/refunds', [
  'body' => 'null',
  'headers' => [
    'Content-Type' => 'application/json',
    'X-SECRET-KEY' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://app.recurrente.com/api/refunds");
var request = new RestRequest(Method.POST);
request.AddHeader("X-SECRET-KEY", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "null", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "X-SECRET-KEY": "<apiKey>",
  "Content-Type": "application/json"
]

let request = NSMutableURLRequest(url: NSURL(string: "https://app.recurrente.com/api/refunds")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Example 2

**Request**

```json
null
```

**Response**

```json
{
  "id": "re_3jfrywsf",
  "status": "succeeded",
  "failure_reason": "string",
  "customer": {
    "id": "string",
    "email": "string",
    "full_name": "string"
  },
  "user_id": "string",
  "account_id": "ac_restaurant",
  "account_refunded_amount_in_cents": 2187,
  "customer_refunded_amount_in_cents": 2500,
  "refund_application_fee": true,
  "transfer_adjustments": [
    {
      "action": "cancel",
      "transfer_setup_id": "string",
      "amount_in_cents": 1,
      "reversal_transfer_id": "string",
      "restoration_transfer_id": "string",
      "restored_at": "2024-01-15T09:30:00Z"
    }
  ],
  "currency": "GTQ",
  "created_at": "2024-01-15T09:30:00Z",
  "voided_at": "2024-01-15T09:30:00Z"
}
```

**SDK Code**

```python
import requests

url = "https://app.recurrente.com/api/refunds"

headers = {
    "X-SECRET-KEY": "<apiKey>",
    "Content-Type": "application/json"
}

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

print(response.json())
```

```javascript
const url = 'https://app.recurrente.com/api/refunds';
const options = {
  method: 'POST',
  headers: {'X-SECRET-KEY': '<apiKey>', 'Content-Type': 'application/json'},
  body: 'null'
};

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

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://app.recurrente.com/api/refunds"

	payload := strings.NewReader("null")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("X-SECRET-KEY", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://app.recurrente.com/api/refunds")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["X-SECRET-KEY"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "null"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://app.recurrente.com/api/refunds")
  .header("X-SECRET-KEY", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("null")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://app.recurrente.com/api/refunds', [
  'body' => 'null',
  'headers' => [
    'Content-Type' => 'application/json',
    'X-SECRET-KEY' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://app.recurrente.com/api/refunds");
var request = new RestRequest(Method.POST);
request.AddHeader("X-SECRET-KEY", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "null", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "X-SECRET-KEY": "<apiKey>",
  "Content-Type": "application/json"
]

let request = NSMutableURLRequest(url: NSURL(string: "https://app.recurrente.com/api/refunds")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```