# App Pricing Apply

> Apply a localized subscription pricing matrix (produced by app-pricing-localize) to the Apple App Store and/or Google Play. Reads the matrix .md and, per subscription tier, sets each market's price via the App Store Connect API (scheduled price changes) or the Android Publisher API (regional configs). Dry-run by default; only ever lowers. Use when rolling out per-country/per-region subscription p…

- **Type:** Skill
- **Install:** `agentstack add skill-vicoa-ai-app-business-skills-app-pricing-apply`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [vicoa-ai](https://agentstack.voostack.com/s/vicoa-ai)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [vicoa-ai](https://github.com/vicoa-ai)
- **Source:** https://github.com/vicoa-ai/app-business-skills/tree/main/skills/app-pricing-apply

## Install

```sh
agentstack add skill-vicoa-ai-app-business-skills-app-pricing-apply
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# app-pricing-apply

Apply a localized **pricing matrix** to the stores. The input is the matrix `.md` produced by the
sibling **app-pricing-localize** skill — the human-editable source of truth (edit prices there
first). You apply **one subscription tier per run** (one column of the matrix → one store product).

Nothing here computes prices; it only *writes* them. Both appliers **dry-run by default** and
**only ever lower** a market (a target at/above that store's current price is skipped).

## Question flow (ask these, in order)
1. **Which store?** App Store, Google Play, or both.
2. **If both — are the prices the same on both stores?** The matrix is one set of local targets.
   If yes, it drives both stores directly. If no, keep a separate matrix per store (or edit the
   matrix between runs). Currencies that differ per store are handled automatically (see below).
3. **Tier → product mapping.** Each matrix column header (e.g. `Monthly`) is a *tier name*; tell
   the applier which store product it maps to (App Store `productId`, or Google `productId` +
   `basePlanId`). One tier per invocation — loop over the tiers you want.

## Two realities to know before applying
- **App Store — a price DECREASE always reaches existing subscribers.** Apple does not let you
  preserve the higher price for them on a cut, so `preserveCurrentPrice` is a **no-op** for a
  decrease (the record reads back `preserved: false`). It only matters for *increases*, which this
  never does. So: existing + new subscribers in each lowered market renew at the new price.
- **Google Play reprices NEW subscribers only, natively.** Existing subscribers keep their price.
  (This is the one place the two stores genuinely differ.)

## App Store — `scripts/app_store_apply.py`
```bash
export ASC_KEY_ID=XXXXXXXXXX
export ASC_ISSUER_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
export ASC_KEY_PATH=~/.appstoreconnect/private_keys/AuthKey_XXXXXXXXXX.p8   # the .p8, chmod 600
export ASC_BUNDLE_ID=com.example.app

# dry run (default) — shows current → target → resolved price point, per territory:
python3 app_store_apply.py --matrix matrix.md --tier "Monthly" --product com.example.app.monthly

# write it (schedules the changes):
python3 app_store_apply.py --matrix matrix.md --tier "Monthly" --product com.example.app.monthly --apply
```
Encoded gotchas (all learned the hard way):
- **Scheduled change, ~2-day lead.** On an approved subscription you can't re-set the "initial"
  price — every reprice is a *scheduled* change needing a future `startDate`. Apple enforces a
  ~2-day lead that **advances daily**; the script defaults to today+2 and, on a `409 "must be on
  or after DATE"`, retries with the date Apple demands. Override with `--start-date`.
- **Delete-then-create.** A second scheduled record on the *same* start date 409s, so the script
  deletes any existing scheduled record for a territory then creates — idempotent, dup-free,
  re-runnable.
- **Real price points.** It resolves the nearest Apple price point ≤ target itself (the `asc` CLI's
  `--price` *fails* on non-exact values). Transient 5xx are retried; a paginated read finds the
  live price (there can be 300+ price records per sub).
- **Multiple ASC credentials?** These are direct API calls keyed by `ASC_KEY_ID`/`ASC_ISSUER_ID`,
  so there is no `asc --profile` ambiguity — just point the env at the right key.

## Google Play — `scripts/play_store_apply.py`
```bash
pip install google-api-python-client google-auth        # one-time
export GOOGLE_PLAY_KEY=~/play-service-account.json       # SA JSON with Play + financial perms

python3 play_store_apply.py --matrix matrix.md --tier "Monthly" \
    --package com.example.app --product monthly --base-plan base --key "$GOOGLE_PLAY_KEY"     # dry run
python3 play_store_apply.py --matrix matrix.md --tier "Monthly" \
    --package com.example.app --product monthly --base-plan base --key "$GOOGLE_PLAY_KEY" --apply
```
- **Currency is fixed per region by Google.** The matrix target is in *Apple's* currency for a
  market; where Google bills that market in a **different** currency (common: Apple USD vs Google
  local, e.g. `CI(USD≠XOF)`), the raw number is meaningless, so those markets are **skipped and
  listed** — handle them separately. Currency-matched markets apply directly.
- **`regionsVersion` is auto-detected** (the docs' `2022/01` is stale and rejects euro-adopted
  regions like BG/HR). `subscriptions.patch` rewrites `basePlans` wholesale, changing only the
  prices being lowered.
- Market keys are mapped iso3 (matrix) → iso2 (Google region) via `data/territories.csv`.

## How the matrix maps to a store
- The matrix is keyed by **iso3** in each Country cell, e.g. `🇺🇸 United States (USA)`.
- **App Store** territories are iso3 — used directly.
- **Google Play** regions are iso2 — mapped from iso3 via `data/territories.csv`.
- Each tier **column header** is the `--tier` value; you supply the store `--product` it maps to.

## Safety
- **Dry-run by default** — nothing is written without `--apply`.
- **Only ever lowers** — a market already at/below its target is skipped (both stores).
- **Idempotent** — safe to re-run; the App Store path replaces its own scheduled record rather
  than duplicating, and the Google path skips regions already at target.
- **Verify** — both print a read-back count after applying.

## Prereqs
- **Apple:** the App Store Connect `.p8` API key (`chmod 600`) with App Manager/Admin role; `python3` + `PyJWT`.
- **Google:** a service-account JSON with Play Console + financial permissions (the RevenueCat SA
  is typically read-only → `403` on patch); `pip install google-api-python-client google-auth`.
- The **matrix `.md`** from `app-pricing-localize` (run its `matrix` command first).

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [vicoa-ai](https://github.com/vicoa-ai)
- **Source:** [vicoa-ai/app-business-skills](https://github.com/vicoa-ai/app-business-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-vicoa-ai-app-business-skills-app-pricing-apply
- Seller: https://agentstack.voostack.com/s/vicoa-ai
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
