Hi Shopify team
Note: This is specifically about the migration token exchange (
expiring=1) idempotency/retry, which differs from existing offline-vs-online token threads (e.g. rate-limit / bulk-operation visibility). I couldn’t find an existing answer for the migration-exchange retry case.
Context
We’re migrating our public app’s existing non-expiring offline access tokens to expiring ones ahead of the Jan 1, 2027 requirement. For already-installed shops we plan to run a one-time, irreversible migration exchange as a background batch across ALL shops (no merchant reinstall), using:
POST https://{shop}/admin/oauth/access_token
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
subject_token=<existing NON-expiring offline token>
subject_token_type=urn:shopify:params:oauth:token-type:offline-access-token
requested_token_type=urn:shopify:params:oauth:token-type:offline-access-token
expiring=1
Already confirmed (so no need to repeat): the original non-expiring token is revoked on successful exchange, the migration is irreversible, and if we fail to persist the new token the shop must reinstall.
My open questions are specifically about retrying this migration exchange, which the docs cover for the refresh_token grant but NOT for the migration exchange.
Q-A: Idempotency / replay window
The refresh_token grant documents a replay window — “Shopify returns the same refreshed token response for up to 1 hour after the original refresh.”
Does the same replay window apply to the migration exchange above? i.e. if I resend the identical request with the same subject_token within some window after Shopify already processed it, do I get back the same access_token / refresh_token?
Q-B: Safe retry on transient failures
For refresh_token, the docs say to treat network errors / timeouts / 5xx / 429 as transient and retry with the same token.
Does the same retry-safety apply to the migration exchange? Concretely: if I send the migration exchange and the response is lost (timeout), so I don’t know whether Shopify processed it —
- If I retry with the same
subject_token, will Shopify return the same new token (recoverable)? - Or, since the old token may already be revoked, does the retry fail and leave the new token unrecoverable → shop orphaned (reinstall required)?
Why this matters
This runs once, irreversibly, across all existing shops. Whether a transient network blip during the batch can orphan a shop (vs. being harmlessly retryable) directly determines our failure-recovery design and the blast radius of the migration.
Is there any documented / guaranteed behavior here — a replay window, safe-retry guidance, or an idempotency-key mechanism — for the migration exchange specifically? Thanks!