Refund a Commission

Record a refund of a tracked payment and adjust or void the matching affiliate commission.

POST/api/v1/refunds

Use 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:

ParameterTypeDescription
commission_id
stringAnderro's internal commission id. Cleanest pointer - get it from GET /api/v1/commissions and store it alongside your order in your database.
external_id
stringYour 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
stringCustomer email. Fallback heuristic; must be combined with payment_amount_cents to disambiguate multiple payments from the same customer.
payment_amount_cents
integerRequired when identifying by email. Must exactly match the original payment amount.

Optional parameters

ParameterTypeDescription
refund_amount_cents
integerRefund amount in cents. Omitted = full refund. Smaller value = partial refund (commission scaled proportionally, status unchanged). Larger than the original payment returns 422.
reason
stringFree-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):

bash
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:

bash
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:

bash
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:

bash
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

200Refund applied
json
{
  "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.

400Validation error
json
{
  "error": "Validation failed",
  "details": {
    "fieldErrors": {},
    "formErrors": ["Provide one of: commission_id, external_id, or (email + payment_amount_cents)"]
  }
}
404No matching payment found
json
{
  "error": "No payment matching that identifier was found for this product"
}
409Commission already fully refunded
json
{
  "error": "Commission already fully refunded",
  "details": {
    "commission_id": "comm_abc123"
  }
}
422Refund amount exceeds the original payment
json
{
  "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 statusEffect 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.
rejectedAlready 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.