curl --request POST \
--url https://api.bachs.io/v1/refunds \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"charge_id": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f",
"reference": "RF-20260713-0042",
"amount": "29.00",
"fee_bearer": "org",
"reason": "Customer requested cancellation",
"idempotency_key": "RF-20260713-0042"
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
charge_id: 'ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f',
reference: 'RF-20260713-0042',
amount: '29.00',
fee_bearer: 'org',
reason: 'Customer requested cancellation',
idempotency_key: 'RF-20260713-0042'
})
};
fetch('https://api.bachs.io/v1/refunds', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.bachs.io/v1/refunds"
payload = {
"charge_id": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f",
"reference": "RF-20260713-0042",
"amount": "29.00",
"fee_bearer": "org",
"reason": "Customer requested cancellation",
"idempotency_key": "RF-20260713-0042"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.bachs.io/v1/refunds"
payload := strings.NewReader("{\n \"charge_id\": \"ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f\",\n \"reference\": \"RF-20260713-0042\",\n \"amount\": \"29.00\",\n \"fee_bearer\": \"org\",\n \"reason\": \"Customer requested cancellation\",\n \"idempotency_key\": \"RF-20260713-0042\"\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))
}{
"refund_id": "b7f2c41a-9d38-4e6b-8c15-2a7d0e934f61",
"charge_id": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f",
"reference": "RF-20260713-0042",
"status": "processing",
"requested_amount": "29.00",
"refunded_amount": null,
"refund_fee_amount": "0.00",
"fee_bearer": "org",
"reason": "Customer requested cancellation",
"created_at": "2026-07-13T14:20:00.000Z",
"updated_at": "2026-07-13T14:20:00.000Z",
"completed_at": null
}{
"detail": "Invalid request parameters",
"error_code": "VALIDATION_ERROR",
"errors": [
{
"field": "amount",
"message": "Amount must be a positive decimal string",
"type": "value_error"
}
]
}{
"detail": "Invalid API key",
"error_code": "UNAUTHORIZED"
}{
"detail": "API key does not have permission for this operation",
"error_code": "FORBIDDEN"
}{
"detail": "Resource not found",
"error_code": "NOT_FOUND"
}{
"detail": "Duplicate request detected",
"error_code": "CONFLICT"
}{
"detail": "Rate limit exceeded. Please retry after a few seconds.",
"error_code": "TOO_MANY_REQUESTS"
}{
"detail": "An unexpected error occurred. Please try again later.",
"error_code": "INTERNAL_SERVER_ERROR"
}Create a refund
Create a refund for a completed payment. Only one refund can be created per charge.
curl --request POST \
--url https://api.bachs.io/v1/refunds \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"charge_id": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f",
"reference": "RF-20260713-0042",
"amount": "29.00",
"fee_bearer": "org",
"reason": "Customer requested cancellation",
"idempotency_key": "RF-20260713-0042"
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
charge_id: 'ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f',
reference: 'RF-20260713-0042',
amount: '29.00',
fee_bearer: 'org',
reason: 'Customer requested cancellation',
idempotency_key: 'RF-20260713-0042'
})
};
fetch('https://api.bachs.io/v1/refunds', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.bachs.io/v1/refunds"
payload = {
"charge_id": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f",
"reference": "RF-20260713-0042",
"amount": "29.00",
"fee_bearer": "org",
"reason": "Customer requested cancellation",
"idempotency_key": "RF-20260713-0042"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.bachs.io/v1/refunds"
payload := strings.NewReader("{\n \"charge_id\": \"ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f\",\n \"reference\": \"RF-20260713-0042\",\n \"amount\": \"29.00\",\n \"fee_bearer\": \"org\",\n \"reason\": \"Customer requested cancellation\",\n \"idempotency_key\": \"RF-20260713-0042\"\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))
}{
"refund_id": "b7f2c41a-9d38-4e6b-8c15-2a7d0e934f61",
"charge_id": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f",
"reference": "RF-20260713-0042",
"status": "processing",
"requested_amount": "29.00",
"refunded_amount": null,
"refund_fee_amount": "0.00",
"fee_bearer": "org",
"reason": "Customer requested cancellation",
"created_at": "2026-07-13T14:20:00.000Z",
"updated_at": "2026-07-13T14:20:00.000Z",
"completed_at": null
}{
"detail": "Invalid request parameters",
"error_code": "VALIDATION_ERROR",
"errors": [
{
"field": "amount",
"message": "Amount must be a positive decimal string",
"type": "value_error"
}
]
}{
"detail": "Invalid API key",
"error_code": "UNAUTHORIZED"
}{
"detail": "API key does not have permission for this operation",
"error_code": "FORBIDDEN"
}{
"detail": "Resource not found",
"error_code": "NOT_FOUND"
}{
"detail": "Duplicate request detected",
"error_code": "CONFLICT"
}{
"detail": "Rate limit exceeded. Please retry after a few seconds.",
"error_code": "TOO_MANY_REQUESTS"
}{
"detail": "An unexpected error occurred. Please try again later.",
"error_code": "INTERNAL_SERVER_ERROR"
}Authorizations
Bearer token authentication. Pass your API key as Authorization: Bearer sk_.... See Authentication for keys, scopes, and sandbox vs production.
Body
The ID of the payment to refund.
"ch_1a2b3c4d5e6f"
Your unique identifier for this refund. Must be unique per account and environment.
128"refund_9876"
Destination wallet address for crypto refunds. Required when the charge currency is a cryptocurrency.
255"0xabc123def456"
Optional partial refund amount in the charge settlement currency. Omit to refund the full remaining refundable balance.
"10.00"
Who absorbs the refund fee. org: the fee is charged to your balance on top of the amount returned. customer: the fee is taken out of what the customer receives. Defaults to the fee handling set on your account. Case is ignored.
org, customer "org"
Human-readable reason for the refund.
500"Customer requested cancellation"
A key you supply to make this request idempotent. If you send the same idempotency_key twice for the same charge, the second request returns the existing refund.
255"idem_9f8e7d6c5b"
Test mode only. Force a specific refund outcome. Omit to use the default sandbox outcome.
success, failed "success"
Response
Success - Refund created
Pass this to retrieve the refund later.
"rfnd_4b9c2e7a1d35a0f81c62"
The charge whose funds are being returned. A charge carries at most one refund that did not fail, so this value appears on one refund at a time.
"ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f"
The reference you supplied on creation.
"refund_9876"
Where the refund has reached. processing: the return has been accepted and your balance is already reserved, but the outcome is not yet known. success: the funds have reached the customer; this is final and cannot be reversed. failed: the return did not go through and the reserved balance has been released. This is final for this refund, but it moved no money, so the payment becomes refundable again and you can create a new refund for it.
processing, success, failed "processing"
The refund amount you requested, in the charge's settlement currency.
"29.00"
The amount actually returned to the customer. Null until the refund completes or partially settles.
null
Fee charged for this refund, in the charge's settlement currency. "0" if no fee applies.
"0.00"
Who absorbs the refund fee. org: the fee is charged to your balance on top of the amount returned. customer: the fee is taken out of what the customer receives.
org, customer "org"
The reason you provided, or null if none was given.
"Customer requested cancellation"
ISO 8601 timestamp when the refund was created.
"2026-04-27T12:00:00Z"
ISO 8601 timestamp of the last status update.
"2026-04-27T12:00:00Z"
ISO 8601 timestamp when the refund reached a terminal status (success or failed). Null while still processing.
null

