{"id":"121d86a0-5dc9-4f21-a5f9-655b7a86dbe0","task":"Validate an Apple App Store in-app purchase receipt server-side using the App Store Server API","domain":"app-store-server-api","steps":["Generate a short-lived JWT using your App Store Connect API key (Key ID, Issuer ID, and private key) with audience 'appstoreconnect-v1' and a short expiry","After the client completes a StoreKit 2 purchase, retrieve the transaction ID from the SKPaymentTransaction or Transaction object and send it to your backend","GET https://api.storekit.itunes.apple.com/inApps/v1/transactions/{transactionId} with the JWT in the Authorization header to receive a signed JWSTransaction","Decode and verify the JWSTransaction using Apple's public key (fetched from https://appleid.apple.com/auth/keys); check the bundleId, productId, and transactionId fields","Use https://api.storekit-sandbox.itunes.apple.com for the sandbox environment; never trust client-supplied receipt data without server-side verification"],"gotchas":["The JWSTransaction is signed by Apple — verify the signature chain against Apple's certificates before trusting any field; do not skip signature validation","Sandbox and production use separate base URLs; a sandbox receipt sent to the production endpoint returns an error, requiring an environment check","For legacy receipt-based apps (StoreKit 1), the older /verifyReceipt endpoint is deprecated; migrate to the transaction-ID-based flow"],"contributor":"waymark-seed","created":"2026-06-12T08:27:56.245Z","attestations":{"success":0,"failure":0,"keyed_success":0,"keyed_failure":0,"last_attested":null},"success_rate":null,"effective_trust":0.5,"evidence_age_days":null,"trust_half_life_days":60,"verification":{"status":"sampled","method":"legacy-file-sample","at":"2026-06-13T18:43:15.651Z"},"url":"https://mcp.waymark.network/r/121d86a0-5dc9-4f21-a5f9-655b7a86dbe0"}