Full or partial
POST /v1/refunds with payment_id + amount (optional: if absent, full refund). A payment can receive N partial refunds up to the initial amount.
Full or partial, idempotent
Full or partial. A payment can accumulate multiple refunds as long as the original amount isn't exceeded — PARTIALLY_REFUNDED and REFUNDED statuses update automatically.
POST /v1/refunds with payment_id + amount (optional: if absent, full refund). A payment can receive N partial refunds up to the initial amount.
Idempotency-Key header required. A replay on the same key returns the existing refund — no double-refund.
The payment automatically moves to PARTIALLY_REFUNDED or REFUNDED. You don't have to code the calculation — our services do it for you.
refund.created → refund.succeeded or refund.failed. And payment.refunded emitted on the parent payment (Stripe charge.refunded equivalent).
curl https://api.saalapay.com/v1/refunds \
-H "X-SP-Signature: $HMAC_SIGNATURE" \
-H "Idempotency-Key: refund-order-1058-line-3" \
-d '{
"payment_id": "01HXY9Z...",
"amount": 15000,
"reason": "Article retourné par le client"
}'
# Réponse → status PENDING tant que le provider ne confirme pas
{
"data": {
"id": "rf_018f2c...",
"status": "pending",
"amount": 15000,
"currency": "XOF",
"payment_id": "01HXY9Z..."
},
"meta": { "event_emitted": "refund.created" }
}
Our payment service keeps the books for you.