OneShot

All packsApp Store MachinerySolve

app store server notifications v2 idempotency duplicate

Apple retries notifications for 3 days -- your handler has to expect duplicates

Apple retries a Server Notification up to 5 times over 3 days on any non-200 response, so the same notification arriving twice has to be a safe no-op, not a double-processed event.

This is one of the things App Store Machinery already handles. Sell subscriptions and one-time unlocks in your iOS app, and get it through App Review.

Buy for $1293 of 3 clean-room builds passed · full refund if it fails on your machine

Is this you?

App Store Server Notifications V2 aren't guaranteed exactly-once -- Apple explicitly retries up to 5 times over 3 days for anything that doesn't return 200 promptly. A handler that processes every incoming notification as if it's new, with no dedupe check, can apply the same renewal or refund event's side effects more than once if a retry happens (a slow response, a transient error, a deploy mid-delivery-window) -- and the fix isn't just "be faster," it's handling the duplicate correctly when one arrives anyway.

Why this one is easy to get wrong

A notification handler that just processes whatever payload arrives works correctly in every test that sends each notification once, which is how manual testing and most integration tests are naturally structured -- Apple's specific retry behavior (5 attempts, 3-day window, triggered by anything other than a fast 200) is a platform detail that has to be read from Apple's own docs, not something that falls out of implementing "handle this webhook."

What you get instead

Decision 7 makes notificationUUID a UNIQUE database column and treats a duplicate insert as a 200 no-op -- correct and safe regardless of how many times Apple retries. The handler is also required to respond within 5 seconds by persisting first and doing any heavier work after, and unknown notification types are stored, logged, and still answered with 200, since Apple adding new types over time must never turn into an unhandled-type 500 that triggers pointless retries.

Source: ARCHITECTURE.md decision 7 — checkable in the pack you receive

How you actually use this

You don’t install a library or wire up an SDK. Your own coding agent builds the code in your project, and you keep it — no runtime dependency on us.

  1. Step 1

    Download and unzip

    You get a folder: the docs that tell an agent what to build, a starting skeleton, and the test suite that decides when it's done.

  2. Step 2

    Open it in Claude Code or Cursor

    Point your coding agent at the folder. Nothing to install, no account with us, no API key.

  3. Step 3

    Paste one prompt

    The pack contains the exact prompt. Paste it as your first message and leave it alone — it works through the build itself, choosing a cheaper or stronger model per task.

  4. Step 4

    Run ./verify.sh

    One command. It prints a pass or fail for every check. Green means the build is done — the same script we ran to produce the receipt on this page.

Typical build: about 21 minutes of your agent working, mostly unattended. Then you integrate the working module into your app the way you would any code you’d written yourself.

Why you can believe this

3 of 3 runs passed

We ran this pack from an empty folder 3 times and published exactly what happened — every check, the model, the token cost, the wall time. Not a testimonial, and not our opinion: the same verify.sh you run yourself. Read the full receipt →

Buy for $12914-day refund if verify.sh fails →

Related problems