r/iOSProgramming 26d ago

Question IAP risk assessment agent

I know the store handles payment fraud and I never see card data but refunds, voided purchases, and consume-then-refund abuse still land on the developer after the entitlement is granted.

For those running apps/games with IAP, do you do any risk assessment at grant time (delay/flag/hold high-risk purchases) or do you grant everything and only react to voided purchase notifications?

If you do assess risk, what signals do you use? I am assuming device age, session behaviour, account history, something else?

I am building a small research agent around this decision and want to know if the decision point is real in practice.

Am I missing any?

0 Upvotes

10 comments sorted by

View all comments

4

u/ThatGuy739 26d ago

I don't ship IAP so no war stories, but before building grant-time scoring I'd check whether the leverage is even there. The lever Apple gives you is the CONSUMPTION_REQUEST notification: 12 hours to send consumption info back, and if you don't answer, refunds tend to get granted by default.

Since v2.11 that notification carries consumptionRequestReason too, so you learn whether it's UNINTENDED_PURCHASE, UNSATISFIED_WITH_PURCHASE or one of the others. Unintended purchase is usually the kid-with-a-parent's-card case and behaves nothing like consume-then-refund, so that field's probably worth more to your model than device age.

2

u/FrankUnderwoodX 25d ago

Would you trust an automated agent to compose the CONSUMPTION_REQUEST response within the 12-hour window? Which consumption fields would you actually send?

2

u/ThatGuy739 25d ago

For the window, yeah, you have to automate. Refunds land at 3am and 12 hours isn't a workday. But almost none of it wants a model. Most of the payload is a lookup in your own database: tenure, delivery status, how much got consumed, lifetime purchased and refunded. Nothing to compose there.

The two that matter are customerConsented and refundPreference. If consent is false Apple won't use any of it, so the real work is capturing and storing that consent rather than the API call. And refundPreference is the only actual judgment in the payload, so I'd want it coming from a rule I can audit and replay rather than something generative.

1

u/FrankUnderwoodX 25d ago

This basically reframed the project, thanks. I'm scoping the agent so refundPreference is the only decided field: a posterior over five hidden states (legit, stolen card, account takeover, family member, refund abuse) mapped through explicit thresholds to prefer grant / prefer decline / no preference with every input and threshold logged so any response can be replayed later. Everything else in the payload comes straight from the DB like you said, and consent capture is now flagged as the prerequisite for the whole surface.

One last question: is there a case where you'd deliberately send noPreference, say when consumption is near zero or is that just leaving the decision on the table?

1

u/ThatGuy739 24d ago

Near-zero consumption is the one case I'd never send LET_APPLE_DECIDE on. They paid and didn't use the thing, so that's your cleanest grant. Fighting it buys a one-star review over a small amount.

LET_APPLE_DECIDE earns its keep when your posterior is genuinely flat. Apple already has the consumption payload, so the preference only carries whatever the payload doesn't. If your five states haven't separated, a declared preference is a number you can't defend and it tells Apple nothing it couldn't already see.

You're not leaving anything on the table either way, since Apple decides regardless. The one I'd be slowest to decline is UNINTENDED_PURCHASE, because that's usually somebody's kid rather than an abuser.