curl --request POST \
--url https://api.qbank.cl/platform/v1/payins/{payinID}/refunds \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"amount": "150.00",
"kind": "refund",
"reason": "solicitud del cliente",
"idempotency_key": "refund-order-8842"
}
'import requests
url = "https://api.qbank.cl/platform/v1/payins/{payinID}/refunds"
payload = {
"amount": "150.00",
"kind": "refund",
"reason": "solicitud del cliente",
"idempotency_key": "refund-order-8842"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
amount: '150.00',
kind: 'refund',
reason: 'solicitud del cliente',
idempotency_key: 'refund-order-8842'
})
};
fetch('https://api.qbank.cl/platform/v1/payins/{payinID}/refunds', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.qbank.cl/platform/v1/payins/{payinID}/refunds",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'amount' => '150.00',
'kind' => 'refund',
'reason' => 'solicitud del cliente',
'idempotency_key' => 'refund-order-8842'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.qbank.cl/platform/v1/payins/{payinID}/refunds"
payload := strings.NewReader("{\n \"amount\": \"150.00\",\n \"kind\": \"refund\",\n \"reason\": \"solicitud del cliente\",\n \"idempotency_key\": \"refund-order-8842\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.qbank.cl/platform/v1/payins/{payinID}/refunds")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"amount\": \"150.00\",\n \"kind\": \"refund\",\n \"reason\": \"solicitud del cliente\",\n \"idempotency_key\": \"refund-order-8842\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.qbank.cl/platform/v1/payins/{payinID}/refunds")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"amount\": \"150.00\",\n \"kind\": \"refund\",\n \"reason\": \"solicitud del cliente\",\n \"idempotency_key\": \"refund-order-8842\"\n}"
response = http.request(request)
puts response.read_body{
"refund_id": "6f1a2b3c-4d5e-4f6a-8b9c-0d1e2f3a4b5c",
"payin_id": "d0135ed5-8e9c-4f8b-a522-8ec100470426",
"account_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"kind": "refund",
"status": "completed",
"currency": "USD",
"local_amount": "150.00",
"usdt_debited": "150.000000",
"requested_by": "account",
"idempotency_key": "refund-order-8842",
"reason": "solicitud del cliente",
"idempotency_hit": true,
"receipt_url": "https://api.qbank.cl/platform/v1/payin-refunds/6f1a2b3c-4d5e-4f6a-8b9c-0d1e2f3a4b5c/receipt",
"created_at": "2026-07-25T13:10:00Z",
"updated_at": "2026-07-25T13:10:03Z"
}{
"refund_id": "6f1a2b3c-4d5e-4f6a-8b9c-0d1e2f3a4b5c",
"payin_id": "d0135ed5-8e9c-4f8b-a522-8ec100470426",
"account_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"kind": "refund",
"status": "completed",
"currency": "USD",
"local_amount": "150.00",
"usdt_debited": "150.000000",
"requested_by": "account",
"idempotency_key": "refund-order-8842",
"reason": "solicitud del cliente",
"receipt_url": "https://api.qbank.cl/platform/v1/payin-refunds/6f1a2b3c-4d5e-4f6a-8b9c-0d1e2f3a4b5c/receipt",
"created_at": "2026-07-25T13:10:00Z",
"updated_at": "2026-07-25T13:10:03Z"
}{
"refund_id": "6f1a2b3c-4d5e-4f6a-8b9c-0d1e2f3a4b5c",
"payin_id": "d0135ed5-8e9c-4f8b-a522-8ec100470426",
"account_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"kind": "refund",
"status": "pending",
"currency": "USD",
"local_amount": "150.00",
"usdt_debited": "150.000000",
"requested_by": "account",
"idempotency_key": "refund-order-8842",
"reconciliation_required": true,
"receipt_url": "https://api.qbank.cl/platform/v1/payin-refunds/6f1a2b3c-4d5e-4f6a-8b9c-0d1e2f3a4b5c/receipt",
"created_at": "2026-07-25T13:10:00Z",
"updated_at": "2026-07-25T13:10:00Z"
}{
"error": "idempotency_key_required",
"message": "idempotency_key is required"
}{
"error": "unauthorized",
"message": "invalid or missing credentials"
}{
"error": "insufficient_funds",
"message": "the account balance is not enough to fund this refund; top up and retry with the same idempotency_key"
}{
"error": "forbidden",
"message": "credentials required"
}{
"error": "not_found",
"message": "resource not found"
}{
"error": "idempotency_conflict",
"message": "another refund with this key is in flight"
}{
"error": "refund_exceeds_payin",
"message": "the requested amount exceeds what is left to refund on this payin"
}Devolver un cobro con tarjeta
Devuelve la plata al tarjetahabiente y reversa el abono en tu saldo. Solo se devuelven cobros con tarjeta en estado credited (refund_not_supported en los demás rieles) — y solo cuando su saldo ya está disponible: un payin credited cuyo settlement sigue pendiente (settlement_pending: true, el saldo cae al llegar settle_at) se rechaza con 422 settlement_pending. Se debita el bruto: la comisión y el spread FX del cobro original NO son reembolsables. La idempotency_key es obligatoria; un reintento devuelve la MISMA devolución con idempotency_hit y jamás manda una segunda devolución al procesador. Exige OTP cuando el llamante es una sesión (las API keys están exentas).
curl --request POST \
--url https://api.qbank.cl/platform/v1/payins/{payinID}/refunds \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"amount": "150.00",
"kind": "refund",
"reason": "solicitud del cliente",
"idempotency_key": "refund-order-8842"
}
'import requests
url = "https://api.qbank.cl/platform/v1/payins/{payinID}/refunds"
payload = {
"amount": "150.00",
"kind": "refund",
"reason": "solicitud del cliente",
"idempotency_key": "refund-order-8842"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
amount: '150.00',
kind: 'refund',
reason: 'solicitud del cliente',
idempotency_key: 'refund-order-8842'
})
};
fetch('https://api.qbank.cl/platform/v1/payins/{payinID}/refunds', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.qbank.cl/platform/v1/payins/{payinID}/refunds",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'amount' => '150.00',
'kind' => 'refund',
'reason' => 'solicitud del cliente',
'idempotency_key' => 'refund-order-8842'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.qbank.cl/platform/v1/payins/{payinID}/refunds"
payload := strings.NewReader("{\n \"amount\": \"150.00\",\n \"kind\": \"refund\",\n \"reason\": \"solicitud del cliente\",\n \"idempotency_key\": \"refund-order-8842\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.qbank.cl/platform/v1/payins/{payinID}/refunds")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"amount\": \"150.00\",\n \"kind\": \"refund\",\n \"reason\": \"solicitud del cliente\",\n \"idempotency_key\": \"refund-order-8842\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.qbank.cl/platform/v1/payins/{payinID}/refunds")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"amount\": \"150.00\",\n \"kind\": \"refund\",\n \"reason\": \"solicitud del cliente\",\n \"idempotency_key\": \"refund-order-8842\"\n}"
response = http.request(request)
puts response.read_body{
"refund_id": "6f1a2b3c-4d5e-4f6a-8b9c-0d1e2f3a4b5c",
"payin_id": "d0135ed5-8e9c-4f8b-a522-8ec100470426",
"account_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"kind": "refund",
"status": "completed",
"currency": "USD",
"local_amount": "150.00",
"usdt_debited": "150.000000",
"requested_by": "account",
"idempotency_key": "refund-order-8842",
"reason": "solicitud del cliente",
"idempotency_hit": true,
"receipt_url": "https://api.qbank.cl/platform/v1/payin-refunds/6f1a2b3c-4d5e-4f6a-8b9c-0d1e2f3a4b5c/receipt",
"created_at": "2026-07-25T13:10:00Z",
"updated_at": "2026-07-25T13:10:03Z"
}{
"refund_id": "6f1a2b3c-4d5e-4f6a-8b9c-0d1e2f3a4b5c",
"payin_id": "d0135ed5-8e9c-4f8b-a522-8ec100470426",
"account_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"kind": "refund",
"status": "completed",
"currency": "USD",
"local_amount": "150.00",
"usdt_debited": "150.000000",
"requested_by": "account",
"idempotency_key": "refund-order-8842",
"reason": "solicitud del cliente",
"receipt_url": "https://api.qbank.cl/platform/v1/payin-refunds/6f1a2b3c-4d5e-4f6a-8b9c-0d1e2f3a4b5c/receipt",
"created_at": "2026-07-25T13:10:00Z",
"updated_at": "2026-07-25T13:10:03Z"
}{
"refund_id": "6f1a2b3c-4d5e-4f6a-8b9c-0d1e2f3a4b5c",
"payin_id": "d0135ed5-8e9c-4f8b-a522-8ec100470426",
"account_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"kind": "refund",
"status": "pending",
"currency": "USD",
"local_amount": "150.00",
"usdt_debited": "150.000000",
"requested_by": "account",
"idempotency_key": "refund-order-8842",
"reconciliation_required": true,
"receipt_url": "https://api.qbank.cl/platform/v1/payin-refunds/6f1a2b3c-4d5e-4f6a-8b9c-0d1e2f3a4b5c/receipt",
"created_at": "2026-07-25T13:10:00Z",
"updated_at": "2026-07-25T13:10:00Z"
}{
"error": "idempotency_key_required",
"message": "idempotency_key is required"
}{
"error": "unauthorized",
"message": "invalid or missing credentials"
}{
"error": "insufficient_funds",
"message": "the account balance is not enough to fund this refund; top up and retry with the same idempotency_key"
}{
"error": "forbidden",
"message": "credentials required"
}{
"error": "not_found",
"message": "resource not found"
}{
"error": "idempotency_conflict",
"message": "another refund with this key is in flight"
}{
"error": "refund_exceeds_payin",
"message": "the requested amount exceeds what is left to refund on this payin"
}Autorizaciones
JWT de sesión (de register/login) o llave de API (pk_...).
X-API-Key: <token> se acepta como header alternativo.
Encabezados
Token OTP de un solo uso (ver la guía de OTP). Solo para llamantes con sesión.
Parámetros de ruta
Cuerpo
Respuesta
Reintento con la misma clave de idempotencia — la MISMA devolución, con idempotency_hit.
chargeback lo impone el emisor de la tarjeta — se asienta automático y puede dejar el saldo negativo.
refund, void, chargeback pending, completed, failed Moneda del payin original.
Monto debitado del saldo USDT. La comisión y el spread FX del payin original NO se devuelven.
account, admin, issuer Presente cuando status es failed — el débito se revirtió completo.
Presente mientras la devolución está pending — el resultado lo resuelve la conciliación y jamás se re-despacha.
Presente en el webhook payin_refunded — el saldo USDT después del movimiento (puede ser negativo en un contracargo).