In-App Purchase (IAP) API Documentation
Overview
This document outlines the setup process and API endpoints required for validating and handling In-App Purchases (IAP) from Google Play and the Apple App Store.
Google Play Setup
1. API Access
- Ensure API access is enabled in the Google Cloud Console.
- Verify that the service account is linked to the Google Play Console.
2. Install Google Client Library (PHP Example)
Run the following command in your project root:
composer require google/apiclient:^2.12
3. Sample API Request Body to Validate Subscription
{
“package_name”: “com.example.app”,
“product_id”: “monthly_subscription”,
“purchase_token”: “purchase_token_from_client”
}
4. Sample Controller Code to Validate Subscription
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Services\Api\GooglePlayService;
use Illuminate\Http\Request;
class GooglePlayController extends Controller
{
protected $googlePlayService;
public function __construct(GooglePlayService $googlePlayService)
{
$this->googlePlayService = $googlePlayService;
}
public function verifyPurchase(Request $request)
{
$request->validate([
‘package_name’ => ‘required’,
‘product_id’ => ‘required’,
‘purchase_token’ => ‘required’,
]);
try {
$data = $this->googlePlayService->verifySubscription(
$request->package_name,
$request->product_id,
$request->purchase_token
);
if ($data[‘status’] === ‘valid’) {
// Handle successful validation
} else {
// Handle invalid purchase
}
} catch (\Exception $e) {
// Handle exception
}
}
}
5. GooglePlayService Class
namespace App\Services\Api;
use Google_Client;
use Google_Service_AndroidPublisher;
use Carbon\Carbon;
class GooglePlayService
{
protected $client;
public function __construct()
{
$this->client = new Google_Client();
$this->client->setAuthConfig(base_path(‘service.json’)); // Path to your service account file
$this->client->addScope(‘https://www.googleapis.com/auth/androidpublisher’);
}
public function verifySubscription($packageName, $productId, $purchaseToken)
{
$service = new Google_Service_AndroidPublisher($this->client);
try {
$subscription = $service->purchases_subscriptions->get(
$packageName,
$productId,
$purchaseToken
);
$expiryTimeMillis = $subscription->getExpiryTimeMillis();
$startTimeMillis = $subscription->getStartTimeMillis();
return [
‘status’ => ‘valid’,
‘expiry_date’ => Carbon::createFromTimestampMs($expiryTimeMillis)->toDateTimeString(),
‘start_date’ => Carbon::createFromTimestampMs($startTimeMillis)->toDateTimeString(),
‘auto_renewing’ => $subscription->getAutoRenewing(),
‘purchase_state’ => $subscription->getPurchaseState() ?? null,
];
} catch (\Exception $e) {
// Handle exception
}
}
}
Google Webhook Setup
- Ensure the webhook URL is added in the Google Cloud Console and is configured for Pub/Sub push.
- The webhook route must not require authentication.
📌 This webhook is automatically triggered by Google for events such as purchase, cancellation, expiry, renewal, etc.
Webhook Endpoint Example
public function webhook(Request $request)
{
// Send immediate response to avoid timeout
response()->json([‘success’ => true])->send();
flush();
try {
// Get raw body
$rawInput = file_get_contents(‘php://input’);
if (empty($rawInput)) {
return;
}
// Decode the outer JSON
$data = json_decode($rawInput, true);
if (!isset($data[‘message’][‘data’])) {
return;
}
// Decode the base64 message
$message = base64_decode($data[‘message’][‘data’]);
$notification = json_decode($message, true);
// Validate the payload structure
if (!isset($notification[‘subscriptionNotification’])) {
throw new \Exception(‘Missing subscriptionNotification key in Google webhook payload.’);
}
$subscriptionNotification = $notification[‘subscriptionNotification’];
$subscriptionId = $subscriptionNotification[‘subscriptionId’] ?? null;
$purchaseToken = $subscriptionNotification[‘purchaseToken’] ?? null;
$notificationType = $subscriptionNotification[‘notificationType’] ?? null;
$packageName = $notification[‘packageName’] ?? null;
switch ($notificationType) {
case 1: // Subscription recovered
// Handle recovery
break;
case 2: // Subscription renewed
// Handle renewal
break;
case 3: // Subscription cancelled
// Handle cancellation
break;
case 4: // Subscription purchased or resubscribed
// Handle new purchase
break;
case 5: // SUBSCRIPTION_ON_HOLD
// Handle expiration
break;
case 6: // SUBSCRIPTION_IN_GRACE_PERIOD
// Handle revocation
break;
case 7: // Subscription restarted
// Handle restart
break;
case 13: //SUBSCRIPTION_EXPIRED
// Reserved for future use
break;
}
} catch (\Exception $e) {
// Log or handle error
}
}
🔗 Reference: Real-time developer notifications (RTDN) – Google Documentation
