Open Source
Overview
This service is built on Laravel / Filament multi-tenant architecture, effectively helping developers prevent fraudulent refunds by instantly processing Apple’s CONSUMPTION_REQUEST notifications and asynchronously returning consumption data.
- Multi-tenant Support
- Multi-language Support (中文 / English / Español / हिन्दी / العربية / Português / Русский / 日本語 / Français)
- Multi-currency Support
- Zero Dependency File+SQLite
or upgrade to Redis+MySQL
- 100% Test Coverage
- Self-hosted App Keys Private keys are only stored in your database
apps
table (symmetric encryption, key generated by your application) - 12 Consumption Fields - Calculate all required Apple fields
- Notification Message Forwarding Apple servers send to current service, current service forwards to your production server
Online Demo
🌐 Demo URL: https://apple-refund-assistant.shiguopeng.cn/
⚠️ Note: The system resets every 30 minutes.
Screenshots
Quick Start
Using Pre-built Image
docker run -d \
-p 8080:8080 \
--name apple-refund-assistant \
--restart=always \
ghcr.io/seth-shi/apple-refund-assistant:latest
Local Build and Run
git clone https://github.com/seth-shi/apple-refund-assistant
cd apple-refund-assistant
## Build image and deploy
./deploy.sh
If you need to mount data
touch database.sqlite
docker run -d \
-p 8080:8080 \
-v $(pwd)/database.sqlite:/var/www/html/database/database.sqlite \
--name apple-refund-assistant \
--restart=always \
ghcr.io/seth-shi/apple-refund-assistant:latest
Consumption Field Strategy
- Documentation: https://developer.apple.com/documentation/appstoreserverapi/consumptionrequest
- Strategy Code: ConsumptionService.php
users
table fields can be updated by other systems
Field | Description | Data Table Source | Calculation Rule |
---|---|---|---|
accountTenure | User registration days | users.register_at |
Current time minus registration time |
appAccountToken | Account token | users.app_account_token |
Needs to be passed by client when creating orders |
consumptionStatus | Consumption status | transactions.expiration_date |
Compare with current time, if expired return consumed |
customerConsented | User consent to provide data | None | Hardcoded true |
deliveryStatus | Whether successfully delivered a functional in-app purchase. | None | Hardcoded 0 (normal delivery) |
lifetimeDollarsPurchased | Total in-app purchase amount | users.purchased_dollars |
Accumulate this field based on Apple transaction events, you can also accumulate manually |
lifetimeDollarsRefunded | Total refund amount | users.refunded_dollars |
Accumulate this field based on Apple refund events, you can also accumulate manually |
platform | Platform | None | Hardcoded 1 (apple) |
playTime | Value of customer app usage time | users.play_seconds |
Your system needs to support updating this field, otherwise it’s 0 |
refundPreference | Expected result of refund request | transactions.expiration_date |
Compare with current time, if expired hope to reject refund |
sampleContentProvided | Whether trial is provided | apps.sample_content_provided |
Configure app when creating application |
userStatus | User status | None | Hardcoded 1 (normal user) |
Future Plans
- Have other ideas or interested in collaboration? Please submit an issue on GitHub - we look forward to your feedback!