Track Refund

Reverse a commission when a sale is refunded

POST /api/v1/track/refund

Reverses the affiliate commission tied to a previously tracked sale. Send one call per refund. Each call's refund_amount_cents is added to what was already refunded on the sale (capped at the sale amount), and the commission is reduced proportionally: refunded while part of the sale remains, reversed once all of it is refunded. Omitting refund_amount_cents refunds everything that is left. This is the non-Stripe counterpart to the Stripe refund webhook — both use the same underlying reversal logic.


Authentication

All requests must include your program API key as a Bearer token.

Authorization: Bearer YOUR_PROGRAM_API_KEY
Content-Type: application/json

The key is scoped to a single program. The refund lookup is restricted to sales that belong to the authenticated program.


Request

Fields

transaction_idstringRequired

The transaction_id originally passed to POST /api/v1/track/sale. Used to locate the sale record.

refund_amount_centsintegerOptional

This refund's amount in cents — not the running total refunded so far. Omit or set to 0 to refund the rest of the sale. Must be a positive integer when provided.

refund_idstringOptional

Your own id for this refund (for example the Stripe refund id). Recommended. A refund whose refund_id was already applied is ignored, so retries are safe. Without it, a second call with the same amount for the same sale is treated as a retry and ignored. Ignored when the amount is omitted or 0 (refunding the rest is already safe to retry).

refund_reasonstringOptional

Human-readable reason for the refund. Recorded on the commission and included in partner/advertiser notifications.

Example request body

curl -X POST https://api.affitor.com/api/v1/track/refund \
-H "Authorization: Bearer YOUR_PROGRAM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
  "transaction_id": "txn_abc123",
  "refund_amount_cents": 5000,
  "refund_id": "re_123",
  "refund_reason": "Customer requested cancellation"
}'

Multiple refunds and retries

  • Two partial refunds of $30 and $20 on a $100 sale: send 3000 then 2000 (each with its own refund_id). The commission is reduced by 50% in total.
  • Retries: resending a call with the same refund_id returns status: "skipped" and changes nothing. Without refund_id, the amount is used to detect the retry.

Response

Success — commission reversed or refunded

{
  "success": true,
  "status": "reversed",
  "deductionAmount": 25.00,
  "commission_id": 88
}
FieldTypeDescription
successbooleanAlways true on a 200 response.
statusstring"reversed" (sale fully refunded), "refunded" (partially refunded), or "skipped" (refund already applied, or commission already reversed).
deductionAmountnumberDollar amount deducted from the partner's commission balance. Present when status is reversed or refunded.
commission_idintegerID of the affected commission record.

Success — sale has no commission

{
  "success": true,
  "status": "no_commission",
  "message": "Sale has no commission to reverse"
}

Already-processed refund (idempotent)

{
  "success": true,
  "status": "skipped",
  "reason": "already reversed",
  "commission_id": 88
}

Errors

StatusWhen
400transaction_id is missing from the request body.
401Authorization header is missing, malformed, or the API token is invalid.
404No sale record found for the given transaction_id in the authenticated program.
500Internal error during commission reversal.

Side Effects

When a commission is reversed or refunded, Affitor:

  • transitions the commission to reversed or refunded status
  • deducts the proportional commission amount from the partner's and partner-program's balance (clamped at zero unless the commission was already paid, in which case the balance can go negative)
  • sends an in-app notification to the partner
  • sends a manual-review warning to the advertiser if the commission had already been paid out

These side effects are fire-and-forget and do not affect the HTTP response.


© 2026 Affitor