/api/v1/refundsUse this endpoint when a customer is refunded for a payment that was originally attributed to an affiliate. Anderro will locate the matching commission and either void it (full refund) or proportionally reduce it (partial refund), and emit a commission.refunded webhook so your systems stay in sync.
The endpoint is idempotent: a commission that has already been fully refunded returns 409 instead of being clawed back a second time.
Identifying the payment
You must provide exactly one identifier strategy. Pick the strongest one you have:
| Parameter | Type | Description |
|---|---|---|
commission_id | string | Anderro's internal commission id. Cleanest pointer - get it from GET /api/v1/commissions and store it alongside your order in your database. |
external_id | string | Your own transaction id (Stripe charge id, Paddle transaction id, internal order id). Recommended for production integrations - the merchant already has this id without any new storage. |
email | string | Customer email. Fallback heuristic; must be combined with payment_amount_cents to disambiguate multiple payments from the same customer. |
payment_amount_cents | integer | Required when identifying by email. Must exactly match the original payment amount. |
Optional parameters
| Parameter | Type | Description |
|---|---|---|
refund_amount_cents | integer | Refund amount in cents. Omitted = full refund. Smaller value = partial refund (commission scaled proportionally, status unchanged). Larger than the original payment returns 422. |
reason | string | Free-form reason (max 500 chars). Stored on the commission and forwarded to the affiliate in the notification email. |
Example requests
Full refund via commission id (recommended):
curl -X POST https://anderro.com/api/v1/refunds \
-H "Content-Type: application/json" \
-H "x-api-key: sk_your_secret_key" \
-d '{
"commission_id": "comm_abc123",
"reason": "Customer requested refund within trial period"
}'
Full refund via Stripe charge id:
curl -X POST https://anderro.com/api/v1/refunds \
-H "Content-Type: application/json" \
-H "x-api-key: sk_your_secret_key" \
-d '{
"external_id": "ch_3NqLm12abcdef",
"reason": "Chargeback"
}'
Partial refund:
curl -X POST https://anderro.com/api/v1/refunds \
-H "Content-Type: application/json" \
-H "x-api-key: sk_your_secret_key" \
-d '{
"external_id": "ch_3NqLm12abcdef",
"refund_amount_cents": 1500,
"reason": "Pro-rata refund for canceled mid-month"
}'
Fallback via email + amount:
curl -X POST https://anderro.com/api/v1/refunds \
-H "Content-Type: application/json" \
-H "x-api-key: sk_your_secret_key" \
-d '{
"email": "[email protected]",
"payment_amount_cents": 4900
}'
Responses
{
"data": {
"commission_id": "comm_abc123",
"partnership_id": "p_xyz789",
"payment_amount_cents": 4900,
"refund_amount_cents": 4900,
"previous_commission_cents": 980,
"new_commission_cents": 0,
"status": "refunded",
"fully_refunded": true
}
}
new_commission_cents is what the commission is now worth after the refund (zero on a full refund, proportionally reduced on a partial refund). status is the new commission status - refunded on a full refund, unchanged (pending / approved / paid) on a partial refund.
{
"error": "Validation failed",
"details": {
"fieldErrors": {},
"formErrors": ["Provide one of: commission_id, external_id, or (email + payment_amount_cents)"]
}
}
{
"error": "No payment matching that identifier was found for this product"
}
{
"error": "Commission already fully refunded",
"details": {
"commission_id": "comm_abc123"
}
}
{
"error": "refund_amount_cents must be > 0 and <= the original payment",
"details": {
"payment_amount_cents": 4900
}
}
How refunds affect commissions
The effect of a refund depends on the commission's current status:
| Current status | Effect of full refund |
|---|---|
pending (in hold period) | Status → refunded, amount zeroed. No money changes hands. |
approved (ready for payout) | Status → refunded, amount zeroed. Clawback against the next payout batch. |
paid (already paid out) | Status → refunded, amount zeroed. Affiliate is notified by email - the business is responsible for recovering the funds on their next reconciliation. |
rejected | Already voided; refund is a no-op. |
Partial refunds proportionally reduce amount_cents but leave the status unchanged. Multiple partial refunds against the same commission accumulate until they sum to the full payment, at which point the commission flips to refunded.
Idempotency
The endpoint is safe to call multiple times. A commission that's already fully refunded returns 409 with the existing commission_id. Partial refunds accumulate via the cumulative refunded_amount_cents field, so retrying the same partial refund will not double-deduct.
Affiliate notification
When a refund either fully voids a commission or claws back a commission that was already paid out, the affiliate receives a transactional email notification. There is no opt-out - losing earned income is information the affiliate must receive.