curl --request POST \
--url https://api-dashboard.payra.com/v1/refunds \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"payment": "pay_test_7Hs2kQ9mL1pXv4cR8tWzAbCdEf",
"amount": 2500,
"reason": "Customer returned the item"
}
'import requests
url = "https://api-dashboard.payra.com/v1/refunds"
payload = {
"payment": "pay_test_7Hs2kQ9mL1pXv4cR8tWzAbCdEf",
"amount": 2500,
"reason": "Customer returned the item"
}
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({
payment: 'pay_test_7Hs2kQ9mL1pXv4cR8tWzAbCdEf',
amount: 2500,
reason: 'Customer returned the item'
})
};
fetch('https://api-dashboard.payra.com/v1/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-dashboard.payra.com/v1/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([
'payment' => 'pay_test_7Hs2kQ9mL1pXv4cR8tWzAbCdEf',
'amount' => 2500,
'reason' => 'Customer returned the item'
]),
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-dashboard.payra.com/v1/refunds"
payload := strings.NewReader("{\n \"payment\": \"pay_test_7Hs2kQ9mL1pXv4cR8tWzAbCdEf\",\n \"amount\": 2500,\n \"reason\": \"Customer returned the item\"\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-dashboard.payra.com/v1/refunds")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"payment\": \"pay_test_7Hs2kQ9mL1pXv4cR8tWzAbCdEf\",\n \"amount\": 2500,\n \"reason\": \"Customer returned the item\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-dashboard.payra.com/v1/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 \"payment\": \"pay_test_7Hs2kQ9mL1pXv4cR8tWzAbCdEf\",\n \"amount\": 2500,\n \"reason\": \"Customer returned the item\"\n}"
response = http.request(request)
puts response.read_body{
"object": "refund",
"id": "re_test_3kQ2mL7Hs1pXv4cR8tWzAbCdEf",
"payment": "pay_test_7Hs2kQ9mL1pXv4cR8tWzAbCdEf",
"status": "succeeded",
"amount": 2500,
"currency": "USD",
"reason": "Customer returned the item",
"failure": {
"code": "processing_error",
"message": "The payment could not be processed. Retry later."
},
"livemode": false,
"created_at": "2026-09-22T20:00:00.000Z",
"succeeded_at": "2026-09-22T20:00:01.312Z"
}{
"error": {
"type": "invalid_request_error",
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}Create a refund
Gives money back on one of your payments, in full or in part, through the same path the dashboard uses, so the refund shows in RevOS like any other. Requires an Idempotency-Key: the same key with the same body returns the same refund. One refund at a time per payment: while one is pending, another is refused with 409.
curl --request POST \
--url https://api-dashboard.payra.com/v1/refunds \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"payment": "pay_test_7Hs2kQ9mL1pXv4cR8tWzAbCdEf",
"amount": 2500,
"reason": "Customer returned the item"
}
'import requests
url = "https://api-dashboard.payra.com/v1/refunds"
payload = {
"payment": "pay_test_7Hs2kQ9mL1pXv4cR8tWzAbCdEf",
"amount": 2500,
"reason": "Customer returned the item"
}
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({
payment: 'pay_test_7Hs2kQ9mL1pXv4cR8tWzAbCdEf',
amount: 2500,
reason: 'Customer returned the item'
})
};
fetch('https://api-dashboard.payra.com/v1/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-dashboard.payra.com/v1/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([
'payment' => 'pay_test_7Hs2kQ9mL1pXv4cR8tWzAbCdEf',
'amount' => 2500,
'reason' => 'Customer returned the item'
]),
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-dashboard.payra.com/v1/refunds"
payload := strings.NewReader("{\n \"payment\": \"pay_test_7Hs2kQ9mL1pXv4cR8tWzAbCdEf\",\n \"amount\": 2500,\n \"reason\": \"Customer returned the item\"\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-dashboard.payra.com/v1/refunds")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"payment\": \"pay_test_7Hs2kQ9mL1pXv4cR8tWzAbCdEf\",\n \"amount\": 2500,\n \"reason\": \"Customer returned the item\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-dashboard.payra.com/v1/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 \"payment\": \"pay_test_7Hs2kQ9mL1pXv4cR8tWzAbCdEf\",\n \"amount\": 2500,\n \"reason\": \"Customer returned the item\"\n}"
response = http.request(request)
puts response.read_body{
"object": "refund",
"id": "re_test_3kQ2mL7Hs1pXv4cR8tWzAbCdEf",
"payment": "pay_test_7Hs2kQ9mL1pXv4cR8tWzAbCdEf",
"status": "succeeded",
"amount": 2500,
"currency": "USD",
"reason": "Customer returned the item",
"failure": {
"code": "processing_error",
"message": "The payment could not be processed. Retry later."
},
"livemode": false,
"created_at": "2026-09-22T20:00:00.000Z",
"succeeded_at": "2026-09-22T20:00:01.312Z"
}{
"error": {
"type": "invalid_request_error",
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "invalid_request_error",
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"param": "<string>"
}
}Authorizations
A secret key, sk_test_... or sk_live_...; a publishable key (pk_...) on the browser routes only
Body
A payment of yours that succeeded.
1 - 64"pay_test_7Hs2kQ9mL1pXv4cR8tWzAbCdEf"
In the smallest unit of the currency. Omit it to refund everything that has not been refunded yet; above that remaining balance the request is refused.
2500
Shown on the refund in RevOS and on the receipt.
1 - 200"Customer returned the item"
Response
The refund
refund "re_test_3kQ2mL7Hs1pXv4cR8tWzAbCdEf"
The payment the money goes back on.
"pay_test_7Hs2kQ9mL1pXv4cR8tWzAbCdEf"
pending while the processor has the refund but has not confirmed it (a later webhook says how it ended); succeeded once the money is on its way back; failed when the processor refused (the create then answers 402 and this object stays readable).
pending, succeeded, failed "succeeded"
In the smallest unit of the currency (cents).
2500
USD, CAD "USD"
"Customer returned the item"
Set when status is failed: why, in the same fixed vocabulary as a payment failure. processing_error is a fault on the way to the processor, safe to retry with a new Idempotency-Key.
Show child attributes
Show child attributes
false
"2026-09-22T20:00:00.000Z"
"2026-09-22T20:00:01.312Z"