Anonymous
Apple In-App Kaufwebhook fehlschlägt mit Status 21002 (ungültige Quittungsdaten)
Post
by Anonymous » 03 Apr 2025, 09:49
Ich bearbeite iOS In-App-Kauf von Webhooks in meinem Node.js-Backend mit Express. Mein Webhook verarbeitet einmalige Einkäufe und überprüft die Transaktion mit Apple. Ich stoße jedoch auf einen "Status": 21002 Fehler bei der Überprüfung der Quittung. < /P>
Code: Select all
import { Request, Response } from "express";
import { formatJsonRes } from "../utils/helper.ts";
import { IosWebhookService } from "../services/iosWebhook.service.ts";
import { IOS_EVENT_TYPES, IOS_EVENT_SUB_TYPES } from "../utils/constants.ts";
const iosWebhookService = new IosWebhookService();
export const unifiedWebhookHandler = async (
req: Request,
res: Response
): Promise => {
try {
const { signedPayload } = req.body;
console.log("reqBody: ", JSON.stringify(req.body, null, 2));
const event =
await iosWebhookService.processWebhookNotification(signedPayload);
console.log("event: ", JSON.stringify(event, null, 2))
switch (event.notificationType) {
case IOS_EVENT_TYPES.ONE_TIME_CHARGE: {
await iosWebhookService.handleCoinPurchaseEvent(event);
await iosWebhookService.verifyTransactionAndContent(signedPayload);
break;
}
...
}
default:
break;
}
return formatJsonRes(res, 200, {
status: "success",
message: "Webhook processed successfully",
});
} catch (error) {
console.error(error);
return formatJsonRes(res, 200, error);
}
};
VerifyTransactionAndContent :
Code: Select all
async verifyTransactionAndContent(signedPayload: any): Promise {
try {
if (!signedPayload) {
console.error("Missing receipt or transaction information");
return false;
}
const verificationResponse =
await this.verifyReceiptWithApple(signedPayload);
if (!verificationResponse) {
console.error("Receipt verification failed");
return false;
}
return true;
} catch (error) {
console.error("Error verifying transaction:", error);
return false;
}
}
verifyReceiptwithApple :
Code: Select all
private readonly RECEIPT_VERIFICATION = {
PRODUCTION_URL: "https://buy.itunes.apple.com/verifyReceipt",
SANDBOX_URL: "https://sandbox.itunes.apple.com/verifyReceipt",
SHARED_SECRET: "b8...",
STATUS_CODES: {
SUCCESS: 0,
SANDBOX_RECEIPT: 21007,
INVALID_RECEIPT: 21002,
AUTH_ERROR: 21003,
},
} as const;
private async verifyReceiptWithApple(
receipt: string
): Promise {
const requestBody = {
"receipt-data": receipt,
password: this.RECEIPT_VERIFICATION.SHARED_SECRET,
"exclude-old-transactions": true,
};
try {
let response = await this.makeVerificationRequest(
this.RECEIPT_VERIFICATION.PRODUCTION_URL,
requestBody
);
if (
response.status ===
this.RECEIPT_VERIFICATION.STATUS_CODES.SANDBOX_RECEIPT
) {
console.log(
"Receipt is from sandbox environment, retrying with sandbox URL..."
);
response = await this.makeVerificationRequest(
this.RECEIPT_VERIFICATION.SANDBOX_URL,
requestBody
);
}
return this.handleVerificationResponse(response);
} catch (error) {
console.error("Error verifying receipt:", error);
return null;
}
}
Relevante Protokolle:
reqbody
Code: Select all
reqBody: {
"signedPayload": "eyJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlFTURDQ0E3YWdBd0lCQ..."
}
Ereignis :
Code: Select all
event: {
"notificationType": "ONE_TIME_CHARGE",
"notificationUUID": "a45cab71-85d5-488f-9a5c-f2207d2cde48",
"environment": "Sandbox",
"transactionInfo": {
"transactionId": "2000000889482224",
"originalTransactionId": "2000000889482224",
"bundleId": "com.chatreal.ai",
"productId": "com.chatreal.coins.silver_pack",
"purchaseDate": 1743665721000,
"originalPurchaseDate": 1743665721000,
"quantity": 1,
"type": "Consumable",
"appAccountToken": "e1ed7fb9-3da8-4bb9-ade2-b66043c3ce16",
"inAppOwnershipType": "PURCHASED",
"signedDate": 1743665732143,
"environment": "Sandbox",
"transactionReason": "PURCHASE",
"storefront": "IND",
"storefrontId": "143467",
"price": 999000,
"currency": "INR",
"appTransactionId": "704346128300986174"
}
}
Fehler :
Code: Select all
Event Type: RECEIPT_VERIFICATION_RESPONSE
Timestamp: 2025-04-03T07:35:34.774Z
Data: {
"status": 21002
}
===============================
Invalid receipt data provided
Receipt verification failed
Der Status 21002 -Fehler zeigt ungültige Quittungsdaten an.>
1743666587
Anonymous
Ich bearbeite iOS In-App-Kauf von Webhooks in meinem Node.js-Backend mit Express. Mein Webhook verarbeitet einmalige Einkäufe und überprüft die Transaktion mit Apple. Ich stoße jedoch auf einen "Status": 21002 Fehler bei der Überprüfung der Quittung. < /P> [code]import { Request, Response } from "express"; import { formatJsonRes } from "../utils/helper.ts"; import { IosWebhookService } from "../services/iosWebhook.service.ts"; import { IOS_EVENT_TYPES, IOS_EVENT_SUB_TYPES } from "../utils/constants.ts"; const iosWebhookService = new IosWebhookService(); export const unifiedWebhookHandler = async ( req: Request, res: Response ): Promise => { try { const { signedPayload } = req.body; console.log("reqBody: ", JSON.stringify(req.body, null, 2)); const event = await iosWebhookService.processWebhookNotification(signedPayload); console.log("event: ", JSON.stringify(event, null, 2)) switch (event.notificationType) { case IOS_EVENT_TYPES.ONE_TIME_CHARGE: { await iosWebhookService.handleCoinPurchaseEvent(event); await iosWebhookService.verifyTransactionAndContent(signedPayload); break; } ... } default: break; } return formatJsonRes(res, 200, { status: "success", message: "Webhook processed successfully", }); } catch (error) { console.error(error); return formatJsonRes(res, 200, error); } }; [/code] [b] VerifyTransactionAndContent [/b]: [code]async verifyTransactionAndContent(signedPayload: any): Promise { try { if (!signedPayload) { console.error("Missing receipt or transaction information"); return false; } const verificationResponse = await this.verifyReceiptWithApple(signedPayload); if (!verificationResponse) { console.error("Receipt verification failed"); return false; } return true; } catch (error) { console.error("Error verifying transaction:", error); return false; } } [/code] [b] verifyReceiptwithApple [/b]: [code]private readonly RECEIPT_VERIFICATION = { PRODUCTION_URL: "https://buy.itunes.apple.com/verifyReceipt", SANDBOX_URL: "https://sandbox.itunes.apple.com/verifyReceipt", SHARED_SECRET: "b8...", STATUS_CODES: { SUCCESS: 0, SANDBOX_RECEIPT: 21007, INVALID_RECEIPT: 21002, AUTH_ERROR: 21003, }, } as const; private async verifyReceiptWithApple( receipt: string ): Promise { const requestBody = { "receipt-data": receipt, password: this.RECEIPT_VERIFICATION.SHARED_SECRET, "exclude-old-transactions": true, }; try { let response = await this.makeVerificationRequest( this.RECEIPT_VERIFICATION.PRODUCTION_URL, requestBody ); if ( response.status === this.RECEIPT_VERIFICATION.STATUS_CODES.SANDBOX_RECEIPT ) { console.log( "Receipt is from sandbox environment, retrying with sandbox URL..." ); response = await this.makeVerificationRequest( this.RECEIPT_VERIFICATION.SANDBOX_URL, requestBody ); } return this.handleVerificationResponse(response); } catch (error) { console.error("Error verifying receipt:", error); return null; } } [/code] [b] Relevante Protokolle: [/b] reqbody [code]reqBody: { "signedPayload": "eyJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlFTURDQ0E3YWdBd0lCQ..." } [/code] Ereignis : [code]event: { "notificationType": "ONE_TIME_CHARGE", "notificationUUID": "a45cab71-85d5-488f-9a5c-f2207d2cde48", "environment": "Sandbox", "transactionInfo": { "transactionId": "2000000889482224", "originalTransactionId": "2000000889482224", "bundleId": "com.chatreal.ai", "productId": "com.chatreal.coins.silver_pack", "purchaseDate": 1743665721000, "originalPurchaseDate": 1743665721000, "quantity": 1, "type": "Consumable", "appAccountToken": "e1ed7fb9-3da8-4bb9-ade2-b66043c3ce16", "inAppOwnershipType": "PURCHASED", "signedDate": 1743665732143, "environment": "Sandbox", "transactionReason": "PURCHASE", "storefront": "IND", "storefrontId": "143467", "price": 999000, "currency": "INR", "appTransactionId": "704346128300986174" } } [/code] [b] Fehler [/b]: [code]Event Type: RECEIPT_VERIFICATION_RESPONSE Timestamp: 2025-04-03T07:35:34.774Z Data: { "status": 21002 } =============================== Invalid receipt data provided Receipt verification failed [/code] Der Status 21002 -Fehler zeigt ungültige Quittungsdaten an.>