Refund policy & rules
How the decision engine answers every request — defaults, ordered rules, consumption evidence, and the deadline fallback.
Every refund request is answered instantly and automatically. The engine evaluates your ordered rules; the first rule whose conditions all match wins; no match falls through to your default preference. There is no manual queue to babysit.
Preferences
| Preference | Apple (refundPreference) | Google (reviewrefund) |
|---|---|---|
decline | DECLINE | DECLINE |
grant | GRANT_FULL | APPROVE |
grant_prorated | GRANT_PRORATED | APPROVE |
no_preference | field omitted | NEUTRAL |
Two knobs live in the dashboard (your app → Refund policy):
- Default preference — sent when no rule matches. Default:
decline. - Deadline fallback — a safety net applied shortly before the store deadline if a request somehow wasn't answered (for example, the store API kept failing). Silence never loses a case.
Rules
Rules are managed via the API today (PUT /v1/apps/{app_id}/policy); a
visual editor is coming. Ordered list, first match wins, all conditions in a
rule must match (AND):
{
"default_preference": "decline",
"rules": [
{
"name": "goodwill: unused and cheap",
"conditions": { "max_usage_count": 0, "max_price_micros": 3000000 },
"action": "grant"
},
{
"name": "repeat refunders never win",
"conditions": { "min_prior_refunds": 2 },
"action": "decline"
}
]
}Available condition keys: product_types, product_ids, countries,
environments, reasons, min_price_micros, max_price_micros,
min_days_since_purchase, max_days_since_purchase, min_usage_count,
max_usage_count, min_prior_refunds. Actions: grant, grant_prorated,
decline, no_preference.
Money is always micros (1,000,000 = one unit of currency).
Consumption evidence
Apple's CONSUMPTION_REQUEST responses include a consumption percentage
(except for auto-renewable subscriptions, where Apple computes it). We build
it from the best data available:
- Real usage — if you stream usage events, we map the buyer's actual usage count through your usage tiers. Defaults: 0 uses → 0%, 1 → 25%, 2–4 → 50%, 5–7 → 75%, 8+ → 100%.
- Estimated — otherwise we estimate from days since purchase. Defaults: day 0 → 25%, ≤2 → 50%, ≤4 → 75%, ≤6 → 85%, 7+ → 100%.
Both tier tables are fully customizable via the policy API (percentages in milliunits: 100000 = 100%).
Evidence settings
- Sample content provided — your app offers a trial/preview before purchase.
- Customer consent obtained — your privacy policy covers sharing consumption data with the stores. Required for Apple responses.
- Auto-acknowledge purchases (Android) — prevents Google auto-refunding unacknowledged purchases after 3 days.
- Fallback safety margin — how many minutes before the store deadline the fallback fires (default 60).
Notification forwarding
Apple allows one notification URL. Forwarding means you never have to choose — RefundHalt relays every notification, raw and untouched, to everything else you use.
Webhooks
RefundHalt's own signed events — structured JSON about every refund case, delivered Stripe-style with HMAC signatures and retries.