{
  "schema": 1,
  "cli_version": "1.9.77",
  "global_flags": [
    {
      "name": "csv",
      "type": "bool",
      "default": "false",
      "usage": "Output as CSV instead of tables",
      "required": false
    },
    {
      "name": "fields",
      "type": "string",
      "default": "",
      "usage": "Comma-separated columns to show, in order",
      "required": false
    },
    {
      "name": "group",
      "type": "string",
      "default": "",
      "usage": "Use a tag group of profiles for multi-profile commands",
      "required": false
    },
    {
      "name": "json",
      "type": "bool",
      "default": "false",
      "usage": "Output pretty-printed JSON instead of tables",
      "required": false
    },
    {
      "name": "ndjson",
      "type": "bool",
      "default": "false",
      "usage": "Output newline-delimited JSON (one row per line)",
      "required": false
    },
    {
      "name": "profile",
      "type": "string",
      "default": "",
      "usage": "Use a named configuration profile",
      "required": false
    },
    {
      "name": "quiet",
      "shorthand": "q",
      "type": "bool",
      "default": "false",
      "usage": "Print only ids, one per line (for scripting)",
      "required": false
    },
    {
      "name": "raw-headers",
      "type": "bool",
      "default": "false",
      "usage": "Use raw API field names as table headers",
      "required": false
    },
    {
      "name": "staged",
      "type": "bool",
      "default": "false",
      "usage": "Stage writes for approval instead of executing them (server records a change id; see `p202 change`)",
      "required": false
    },
    {
      "name": "table",
      "type": "bool",
      "default": "false",
      "usage": "Output tables even when an AI agent would get JSON",
      "required": false
    },
    {
      "name": "wide",
      "type": "bool",
      "default": "false",
      "usage": "Show all columns at full width (no truncation)",
      "required": false
    }
  ],
  "commands": [
    {
      "path": "p202 aff-network",
      "use": "aff-network",
      "aliases": [
        "category"
      ],
      "short": "Manage categories (affiliate networks)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 aff-network create",
      "use": "create",
      "short": "Create a new aff-network",
      "example": "p202 aff-network create --aff-network-name <network_name> --json",
      "runnable": true,
      "flags": [
        {
          "name": "aff-network-name",
          "type": "string",
          "default": "",
          "usage": "Network name (required)",
          "required": true
        },
        {
          "name": "dni-network-id",
          "type": "string",
          "default": "",
          "usage": "DNI network ID",
          "required": false
        },
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        }
      ]
    },
    {
      "path": "p202 aff-network delete",
      "use": "delete <id>",
      "short": "Delete a aff-network",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated aff-network IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 aff-network get",
      "use": "get <id>",
      "short": "Get a aff-network by ID",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 aff-network list",
      "use": "list",
      "short": "List categories (affiliate networks)",
      "runnable": true,
      "flags": [
        {
          "name": "all",
          "type": "bool",
          "default": "false",
          "usage": "Fetch all rows across pages",
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "page",
          "type": "string",
          "default": "",
          "usage": "Page number",
          "required": false
        },
        {
          "name": "resolve-names",
          "type": "bool",
          "default": "false",
          "usage": "Resolve foreign key IDs to names",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 aff-network list",
          "ui_pages": [
            "Setup › Categories"
          ],
          "phrases": [
            "affiliate networks",
            "offer categories"
          ]
        }
      ]
    },
    {
      "path": "p202 aff-network update",
      "use": "update <id>",
      "short": "Update a aff-network",
      "example": "p202 aff-network update <id from p202 aff-network list> --aff-network-name <new value> --json\n  (only the flags given are sent; the rest of the aff-network is unchanged)",
      "runnable": true,
      "flags": [
        {
          "name": "aff-network-name",
          "type": "string",
          "default": "",
          "usage": "Network name",
          "required": false
        },
        {
          "name": "dni-network-id",
          "type": "string",
          "default": "",
          "usage": "DNI network ID",
          "required": false
        }
      ]
    },
    {
      "path": "p202 analytics",
      "use": "analytics",
      "short": "Query performance stats grouped by campaign, traffic source, country, etc. (shorthand for report breakdown)",
      "long": "Stats grouped by one dimension: the shorthand for `p202 report breakdown`.\n\nWith --split-at, compare before and after a date: each value's totals on both\nsides, the change, and the daily rate on each side, so two windows of different\nlengths compare fairly.",
      "example": "p202 analytics --group-by country --period last30\n  p202 analytics --group-by country --split-at 2026-09-04",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by INTERNAL campaign id (from `campaign list`), not the public id in tracking URLs",
          "required": false
        },
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by affiliate network ID",
          "required": false
        },
        {
          "name": "browser-id",
          "type": "string",
          "default": "",
          "usage": "Filter by browser ID (the id of a `--breakdown browser` row)",
          "required": false
        },
        {
          "name": "country-id",
          "type": "string",
          "default": "",
          "usage": "Filter by country ID",
          "required": false
        },
        {
          "name": "days",
          "type": "int",
          "default": "0",
          "usage": "Relative window: the last N×24 hours, ending now (ignored when --period is provided; --period lastN counts whole days from a midnight)",
          "required": false
        },
        {
          "name": "device-type",
          "type": "string",
          "default": "",
          "usage": "Filter by device type ID: 1 Desktop, 2 Mobile, 3 Tablet, 4 Bot (the ids of `--breakdown device_type` rows)",
          "required": false
        },
        {
          "name": "group-by",
          "type": "string",
          "default": "",
          "usage": "Breakdown dimension: campaign, aff_network, ppc_account, ppc_network, landing_page, keyword, country, city, region, browser, platform, device, isp, text_ad, ip, referer, referer_url, device_type, c1, c2, c3, c4, utm_source, utm_medium, utm_campaign, utm_term, utm_content, rotator, rotator_rule (aliases: geo=country, lp=landing_page, network=aff_network, offer=campaign, referrer=referer, referrer_url=referer_url, rule=rotator_rule, source=ppc_account)",
          "allowed_values": [
            "campaign",
            "aff_network",
            "ppc_account",
            "ppc_network",
            "landing_page",
            "keyword",
            "country",
            "city",
            "region",
            "browser",
            "platform",
            "device",
            "isp",
            "text_ad",
            "ip",
            "referer",
            "referer_url",
            "device_type",
            "c1",
            "c2",
            "c3",
            "c4",
            "utm_source",
            "utm_medium",
            "utm_campaign",
            "utm_term",
            "utm_content",
            "rotator",
            "rotator_rule"
          ],
          "value_aliases": {
            "geo": "country",
            "lp": "landing_page",
            "network": "aff_network",
            "offer": "campaign",
            "referrer": "referer",
            "referrer_url": "referer_url",
            "rule": "rotator_rule",
            "source": "ppc_account"
          },
          "required": false
        },
        {
          "name": "ip",
          "type": "string",
          "default": "",
          "usage": "Only clicks from this one IP address, IPv4 or IPv6",
          "required": false
        },
        {
          "name": "isp-id",
          "type": "string",
          "default": "",
          "usage": "Filter by ISP/carrier ID (the id of a `--breakdown isp` row)",
          "required": false
        },
        {
          "name": "keyword",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose keyword contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Filter by landing page ID",
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "method-of-promotion",
          "type": "string",
          "default": "",
          "usage": "Only direct-link clicks or only landing-page clicks: directlink, landingpage",
          "allowed_values": [
            "directlink",
            "landingpage"
          ],
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "period",
          "type": "string",
          "default": "",
          "usage": "Period: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "platform-id",
          "type": "string",
          "default": "",
          "usage": "Filter by platform (OS) ID (the id of a `--breakdown platform` row)",
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC account ID",
          "required": false
        },
        {
          "name": "ppc-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC network ID, or none for the clicks with no traffic source",
          "required": false
        },
        {
          "name": "referer",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose referring URL contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "region-id",
          "type": "string",
          "default": "",
          "usage": "Filter by region ID (the id of a `--breakdown region` row)",
          "required": false
        },
        {
          "name": "show",
          "type": "string",
          "default": "",
          "usage": "Which clicks count (default all): all, real, filtered, filtered_bot, leads; real = not filtered, filtered_bot = filtered as bots, leads = converted",
          "allowed_values": [
            "all",
            "real",
            "filtered",
            "filtered_bot",
            "leads"
          ],
          "required": false
        },
        {
          "name": "sort",
          "type": "string",
          "default": "",
          "usage": "Sort by: total_clicks, total_click_throughs, total_leads, total_income, total_cost, total_net, epc, avg_cpc, conv_rate, roi, cpa, clicks_per_day, conversions_per_day, revenue_per_day (aliases: clicks=total_clicks, conversions=total_leads, cost=total_cost, profit=total_net, revenue=total_income)",
          "allowed_values": [
            "total_clicks",
            "total_click_throughs",
            "total_leads",
            "total_income",
            "total_cost",
            "total_net",
            "epc",
            "avg_cpc",
            "conv_rate",
            "roi",
            "cpa",
            "clicks_per_day",
            "conversions_per_day",
            "revenue_per_day"
          ],
          "value_aliases": {
            "clicks": "total_clicks",
            "conversions": "total_leads",
            "cost": "total_cost",
            "profit": "total_net",
            "revenue": "total_income"
          },
          "required": false
        },
        {
          "name": "sort-dir",
          "type": "string",
          "default": "",
          "usage": "Sort direction: ASC, DESC",
          "allowed_values": [
            "ASC",
            "DESC"
          ],
          "required": false
        },
        {
          "name": "split-at",
          "type": "string",
          "default": "",
          "usage": "Compare before/after this moment: YYYY-MM-DD (00:00 UTC) or unix seconds. Splits the window (--days N, or --time-from/--time-to in unix seconds; default --days 90) into [start, split) and [split, end] and returns one row per value: clicks/conversions/revenue before, after, change, change %, and per-day rates. --sort clicks|conversions|revenue[_per_day] ranks by absolute change (default clicks)",
          "required": false
        },
        {
          "name": "text-ad-id",
          "type": "string",
          "default": "",
          "usage": "Filter by text ad ID",
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "End, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
          "required": false
        }
      ]
    },
    {
      "path": "p202 app",
      "use": "app",
      "aliases": [
        "apps"
      ],
      "short": "App measurement: registered apps, SKAN encodings, postbacks and the report",
      "long": "Register the apps you advertise (from a store link or an app key), decode their\nSKAdNetwork and AdAttributionKit postbacks, and read the report.\n\n  p202 app create --store-link https://apps.apple.com/us/app/summit-run/id990077001\n  p202 goal create --registration-id 1 --name purchase --event purchase\n  p202 app encoding create --registration-id 1 --fine-value 40 --goal-id 12 --revenue-override 4.99\n  p202 app report --group-by registration",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 app create",
      "use": "create",
      "short": "Register an app from a store link or an app key (claims its stored postbacks)",
      "long": "Registers one app. Name it with --store-link (an App Store or Google Play link, a\nmarket:// link, a numeric App Store id or a package name) or with --app-key (the App\nStore id for iOS, the package name for Android; --platform is read from the key's\nshape when left out). The server reads the link, so every client parses it the same way.",
      "runnable": true,
      "flags": [
        {
          "name": "accept-test-signals",
          "type": "string",
          "default": "",
          "usage": "1 = trust test signals for this app (AdAttributionKit development-signed postbacks, Android test installs; integration testing), 0 = store them flagged (default): 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "app-key",
          "type": "string",
          "default": "",
          "usage": "The App Store id (iOS) or the package name (Android)",
          "required": false
        },
        {
          "name": "app-name",
          "type": "string",
          "default": "",
          "usage": "Display name for reports",
          "required": false
        },
        {
          "name": "attribution-window-days",
          "type": "string",
          "default": "",
          "usage": "Android: days after its click an install may begin and still be attributed (1-365, default 7)",
          "required": false
        },
        {
          "name": "ctit-max-seconds",
          "type": "string",
          "default": "",
          "usage": "Android: flag an install that began later than this after its click (60-31536000, default 86400)",
          "required": false
        },
        {
          "name": "ctit-min-seconds",
          "type": "string",
          "default": "",
          "usage": "Android: flag an install that began sooner than this after its click (0-3600, default 10)",
          "required": false
        },
        {
          "name": "event-cap-per-minute",
          "type": "string",
          "default": "",
          "usage": "Android: events one install may post a minute; past it 429 (100-60000, default 200)",
          "required": false
        },
        {
          "name": "fast-goal-policy",
          "type": "string",
          "default": "",
          "usage": "Android: what a fast goal does, one of count, hold: count (pay it and flag it, default) or hold (flag it, never pay)",
          "allowed_values": [
            "count",
            "hold"
          ],
          "required": false
        },
        {
          "name": "fast-goal-seconds",
          "type": "string",
          "default": "",
          "usage": "Android: flag a goal reached sooner than this after its install (0-3600, default 5; 0 flags none)",
          "required": false
        },
        {
          "name": "install-cap-per-minute",
          "type": "string",
          "default": "",
          "usage": "Android: installs the app may report a minute; past it 429 (1-60000, default 300)",
          "required": false
        },
        {
          "name": "integrity-cloud-project-number",
          "type": "string",
          "default": "",
          "usage": "Android: the Google Cloud project NUMBER the SDK requests integrity tokens for (required for observe/require; can be replaced, not cleared)",
          "required": false
        },
        {
          "name": "integrity-mode",
          "type": "string",
          "default": "",
          "usage": "Android: Play Integrity mode, one of off, observe, require: off (default), observe (record verdicts) or require (attribute only a passing verdict); needs `app integrity credential set` first and --integrity-cloud-project-number",
          "allowed_values": [
            "off",
            "observe",
            "require"
          ],
          "required": false
        },
        {
          "name": "notes",
          "type": "string",
          "default": "",
          "usage": "Free-form notes",
          "required": false
        },
        {
          "name": "platform",
          "type": "string",
          "default": "",
          "usage": "Platform (default: read from --app-key or --store-link): ios, android",
          "allowed_values": [
            "ios",
            "android"
          ],
          "required": false
        },
        {
          "name": "store-link",
          "type": "string",
          "default": "",
          "usage": "App Store or Google Play link, market:// link, App Store id or package name",
          "required": false
        },
        {
          "name": "trust-client-revenue",
          "type": "string",
          "default": "",
          "usage": "Android: 1 = revenue the app reports may be paid by a goal valued from it; 0 = stored, never credited (default): 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        }
      ]
    },
    {
      "path": "p202 app delete",
      "use": "delete [id]",
      "short": "Delete an app registration (its SKAN encodings go with it; claimed postbacks keep their owner)",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated app registration IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 app encoding",
      "use": "encoding",
      "aliases": [
        "encodings",
        "skan-encoding",
        "skan-encodings"
      ],
      "short": "SKAN encodings: which conversion value means which goal was reached (mirror of the in-app schema)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 app encoding create",
      "use": "create",
      "short": "Create an encoding (one fine value 0-63 OR one coarse value) for a registration or account-wide",
      "runnable": true,
      "flags": [
        {
          "name": "coarse-value",
          "type": "string",
          "default": "",
          "usage": "Coarse conversion value: low, medium, high",
          "allowed_values": [
            "low",
            "medium",
            "high"
          ],
          "required": false
        },
        {
          "name": "fine-value",
          "type": "string",
          "default": "",
          "usage": "Fine conversion value 0-63",
          "required": false
        },
        {
          "name": "goal-id",
          "type": "string",
          "default": "",
          "usage": "The goal the value means (`p202 goal list --registration-id <id>`; evaluated on the device, so no click window)",
          "required": false
        },
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        },
        {
          "name": "registration-id",
          "type": "string",
          "default": "",
          "usage": "iOS registration the encoding applies to (from `p202 app list`; 0 = account-wide)",
          "required": false
        },
        {
          "name": "revenue-override",
          "type": "string",
          "default": "",
          "usage": "Revenue per decoded postback, instead of the goal's own value (tiered decoding)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 app encoding delete",
      "use": "delete [id]",
      "short": "Delete an encoding",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated SKAN encoding IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 app encoding get",
      "use": "get <id>",
      "short": "Get a SKAN encoding",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 app encoding list",
      "use": "list",
      "short": "List SKAN encodings",
      "runnable": true,
      "flags": [
        {
          "name": "all",
          "type": "bool",
          "default": "false",
          "usage": "Fetch all rows across pages",
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "registration-id",
          "type": "string",
          "default": "",
          "usage": "Only this registration's encodings (0 = the account-wide ones)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 app encoding update",
      "use": "update <id>",
      "short": "Update an encoding (switch kinds with --clear-fine-value/--clear-coarse-value)",
      "long": "Updates fields of an encoding. An encoding always maps exactly ONE conversion\nvalue, so switching one between kinds takes the clear and the replacement in one\ncommand: `update 5 --clear-fine-value --coarse-value high` turns a fine encoding\ninto a coarse one. The clear flags send an explicit JSON null.",
      "runnable": true,
      "flags": [
        {
          "name": "clear-coarse-value",
          "type": "bool",
          "default": "false",
          "usage": "Set coarse_value to null (pair with --fine-value to switch kinds)",
          "required": false
        },
        {
          "name": "clear-fine-value",
          "type": "bool",
          "default": "false",
          "usage": "Set fine_value to null (pair with --coarse-value to switch kinds)",
          "required": false
        },
        {
          "name": "clear-revenue-override",
          "type": "bool",
          "default": "false",
          "usage": "Go back to the goal's own value",
          "required": false
        },
        {
          "name": "coarse-value",
          "type": "string",
          "default": "",
          "usage": "Coarse conversion value: low, medium, high",
          "allowed_values": [
            "low",
            "medium",
            "high"
          ],
          "required": false
        },
        {
          "name": "fine-value",
          "type": "string",
          "default": "",
          "usage": "Fine conversion value 0-63",
          "required": false
        },
        {
          "name": "goal-id",
          "type": "string",
          "default": "",
          "usage": "The goal the value means (`p202 goal list --registration-id <id>`; evaluated on the device, so no click window)",
          "required": false
        },
        {
          "name": "registration-id",
          "type": "string",
          "default": "",
          "usage": "iOS registration the encoding applies to (from `p202 app list`; 0 = account-wide)",
          "required": false
        },
        {
          "name": "revenue-override",
          "type": "string",
          "default": "",
          "usage": "Revenue per decoded postback, instead of the goal's own value (tiered decoding)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 app get",
      "use": "get <id>",
      "short": "Get a registered app by its registration id (from `p202 app list`)",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 app install",
      "use": "install",
      "aliases": [
        "installs"
      ],
      "short": "Android installs: list, inspect, mint a click's install token, simulate the SDK",
      "long": "Android installs reach the server from the SDK (POST /apps/installs); each is\nclassified into a match state (attributed, organic, bad_token, …) with its reason.\n\n  p202 app install list 3 --match-state attributed\n  p202 app install token 3 --click 1042\n  p202 app install simulate 3 --click 1042",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 app install get",
      "use": "get <registration-id> <install-uuid>",
      "short": "Get one install: its referrer, timestamps, match state, reason and trust",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 app install list",
      "use": "list <registration-id>",
      "short": "List an Android registration's installs, newest first, with their match state and reason",
      "runnable": true,
      "flags": [
        {
          "name": "all",
          "type": "bool",
          "default": "false",
          "usage": "Fetch all rows across pages",
          "required": false
        },
        {
          "name": "click-id",
          "type": "string",
          "default": "",
          "usage": "Only installs attributed or matched to this click",
          "required": false
        },
        {
          "name": "ctit-flag",
          "type": "string",
          "default": "",
          "usage": "Only installs whose click-to-install time is: short, ok, long, unmeasured",
          "allowed_values": [
            "short",
            "ok",
            "long",
            "unmeasured"
          ],
          "required": false
        },
        {
          "name": "integrity-state",
          "type": "string",
          "default": "",
          "usage": "Only this Play Integrity state: not_requested, received, missing, pending, valid, invalid, error, skipped",
          "allowed_values": [
            "not_requested",
            "received",
            "missing",
            "pending",
            "valid",
            "invalid",
            "error",
            "skipped"
          ],
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "match-state",
          "type": "string",
          "default": "",
          "usage": "Only this state: attributed, organic, third_party, unavailable, pending_click, bad_token, foreign_click, implausible, outside_window, duplicate_click, pending_integrity, integrity_failed, integrity_unverified",
          "allowed_values": [
            "attributed",
            "organic",
            "third_party",
            "unavailable",
            "pending_click",
            "bad_token",
            "foreign_click",
            "implausible",
            "outside_window",
            "duplicate_click",
            "pending_integrity",
            "integrity_failed",
            "integrity_unverified"
          ],
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "test",
          "type": "string",
          "default": "",
          "usage": "Only test installs (1) or only real ones (0): 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Received-at range start (unix timestamp)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "Received-at range end (unix timestamp)",
          "required": false
        },
        {
          "name": "trusted",
          "type": "string",
          "default": "",
          "usage": "Only this trust class: trusted, refuted, unvouched",
          "allowed_values": [
            "trusted",
            "refuted",
            "unvouched"
          ],
          "required": false
        }
      ]
    },
    {
      "path": "p202 app install simulate",
      "use": "simulate <registration-id> --click <click-id>",
      "short": "Post an SDK-shaped install for a real click, as a device would",
      "long": "Reads the registration (its app token and package), mints the click's install token,\nand posts the install the Android SDK would send to POST /apps/installs — with Google's\ntimestamps placed seconds after the click — then prints the intake's answer. The install\nis real: an attributed one records the install conversion on the click.\n\nResend with the same --install-uuid to see the duplicate answer; --test marks it a test\ninstall (it counts only when the registration accepts test signals).",
      "runnable": true,
      "flags": [
        {
          "name": "click",
          "type": "string",
          "default": "",
          "usage": "The click the install comes from (from `p202 click list`)",
          "required": false
        },
        {
          "name": "delay",
          "type": "int",
          "default": "5",
          "usage": "Seconds from the click to the store click",
          "required": false
        },
        {
          "name": "install-uuid",
          "type": "string",
          "default": "",
          "usage": "The install's id (default: a new one); reuse one to see the duplicate answer",
          "required": false
        },
        {
          "name": "test",
          "type": "bool",
          "default": "false",
          "usage": "Send it as a test install (counts only under accept_test_signals)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 app install token",
      "use": "token <registration-id> --click <click-id>",
      "short": "Show the install token and Google Play store link for one click",
      "long": "Mints [[p202_install_token]] for one of your clicks, exactly as the redirect does,\nand the store link that carries it (…&referrer=p202%3D<token>). A read: nothing is stored.",
      "runnable": true,
      "flags": [
        {
          "name": "click",
          "type": "string",
          "default": "",
          "usage": "The click to sign (from `p202 click list`)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 app integrity",
      "use": "integrity",
      "short": "Play Integrity for an Android app: status, and its Google service-account credential",
      "long": "Play Integrity is opt-in per Android registration. Set the service account first, then\nswitch the mode:\n\n  p202 app integrity credential set 3 --file service-account.json\n  p202 app update 3 --integrity-mode observe --integrity-cloud-project-number 123456789012\n  p202 app integrity status 3\n\nobserve records every install's verdict and changes nothing; require attributes (and pays)\nan install only once its verdict passes. `p202 app install list 3 --integrity-state invalid`\nshows the installs that failed.",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 app integrity credential",
      "use": "credential",
      "short": "Set, rotate or clear the Google service account Play Integrity decodes with",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 app integrity credential clear",
      "use": "clear <registration-id>",
      "short": "Delete the service account (refused while the mode is observe or require, or installs still wait for a verdict)",
      "runnable": true,
      "flags": [
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        }
      ]
    },
    {
      "path": "p202 app integrity credential set",
      "use": "set <registration-id> --file <service-account.json>",
      "short": "Set or rotate the service account (the key is stored encrypted and never shown)",
      "long": "Uploads a Google service-account key file for the app. The account must be able to call\nthe Play Integrity API for the app: the Google Cloud project it belongs to is linked to the\napp in Play Console. Setting it again replaces it (rotation). The server stores the key\nencrypted and answers with the account's email and key id only.",
      "runnable": true,
      "flags": [
        {
          "name": "file",
          "shorthand": "f",
          "type": "string",
          "default": "",
          "usage": "The service-account key file (JSON); \"-\" or omitted reads piped stdin",
          "required": false
        }
      ]
    },
    {
      "path": "p202 app integrity status",
      "use": "status <registration-id>",
      "short": "Show the mode, the credential (never its key), verdict counts and today's decodes",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 app link",
      "use": "link <registration-id>",
      "short": "The store link a campaign should send this app's clicks to, and whether a campaign does",
      "long": "Shows the store link for the app: for Android the Play link with [[p202_install_token]] in\nits referrer (the redirect fills it per click; the SDK reads it back), for iOS the App Store\nlink and the SKAdNetwork/AdAttributionKit Info.plist setup. With --campaign-id it says whether\nthat campaign is ready — its offer URL is the store link and, for Android, the campaign is\nlinked to the app — and with --apply it makes it so (PUT /campaigns/{id}; honours --staged).\nThen `p202 tracker create --aff-campaign-id N` gives the tracking link.",
      "example": "p202 app link 7\n  p202 app link 7 --campaign-id 12 --apply",
      "runnable": true,
      "flags": [
        {
          "name": "apply",
          "type": "bool",
          "default": "false",
          "usage": "Set the campaign's offer URL to the store link and, for Android, link it to the app (and turn URL rotation off when an alternate in rotation is not the app's link)",
          "required": false
        },
        {
          "name": "campaign-id",
          "type": "string",
          "default": "",
          "usage": "Say whether this campaign sends its clicks to the store link (`p202 campaign list`)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 app list",
      "use": "list",
      "short": "List registered apps (both platforms)",
      "runnable": true,
      "flags": [
        {
          "name": "all",
          "type": "bool",
          "default": "false",
          "usage": "Fetch all rows across pages",
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "platform",
          "type": "string",
          "default": "",
          "usage": "Only this platform: ios, android",
          "allowed_values": [
            "ios",
            "android"
          ],
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 app list",
          "ui_pages": [
            "Setup › Mobile Apps"
          ],
          "phrases": [
            "registered apps"
          ]
        }
      ]
    },
    {
      "path": "p202 app notifications",
      "use": "notifications",
      "short": "Traffic-source postbacks the app installs' goals queued, and where each stands",
      "long": "Lists the notification outbox rows for app installs, newest first: the postback URL, its\nkind (reached, correction, retraction) and status — pending (waiting or backing off),\nsent, failed (attempts ran out; last_error says why), cancelled (replaced before it went\nout) or suppressed (a correction the traffic source has no correction URL for).\nmeta.summary counts every status under the same filters.",
      "runnable": true,
      "flags": [
        {
          "name": "all",
          "type": "bool",
          "default": "false",
          "usage": "Fetch all rows across pages",
          "required": false
        },
        {
          "name": "kind",
          "type": "string",
          "default": "",
          "usage": "Only this kind: reached, correction, retraction",
          "allowed_values": [
            "reached",
            "correction",
            "retraction"
          ],
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "registration-id",
          "type": "string",
          "default": "",
          "usage": "Only this app's postbacks (`p202 app list`)",
          "required": false
        },
        {
          "name": "status",
          "type": "string",
          "default": "",
          "usage": "Only this status: pending, sent, failed, cancelled, suppressed",
          "allowed_values": [
            "pending",
            "sent",
            "failed",
            "cancelled",
            "suppressed"
          ],
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Queued at or after (unix timestamp)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "Queued at or before (unix timestamp)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 app postbacks",
      "use": "postbacks",
      "aliases": [
        "postback",
        "pb"
      ],
      "short": "Received SKAdNetwork and AdAttributionKit postbacks (read-only)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 app postbacks get",
      "use": "get <id>",
      "short": "Get one postback, including its attribution signature",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 app postbacks list",
      "use": "list",
      "short": "List received postbacks with filters (registration, protocol, signature state, network, window)",
      "runnable": true,
      "flags": [
        {
          "name": "ad-interaction-type",
          "type": "string",
          "default": "",
          "usage": "Filter: view (view-through) or click: view, click",
          "allowed_values": [
            "view",
            "click"
          ],
          "required": false
        },
        {
          "name": "ad-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by ad network id",
          "required": false
        },
        {
          "name": "all",
          "type": "bool",
          "default": "false",
          "usage": "Fetch all rows across pages",
          "required": false
        },
        {
          "name": "app-id",
          "type": "string",
          "default": "",
          "usage": "Filter by the App Store id the postback itself named (forensic; prefer --registration-id)",
          "required": false
        },
        {
          "name": "campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by SKAN 2/3 campaign id",
          "required": false
        },
        {
          "name": "coarse-conversion-value",
          "type": "string",
          "default": "",
          "usage": "Filter by coarse value: low, medium, high",
          "allowed_values": [
            "low",
            "medium",
            "high"
          ],
          "required": false
        },
        {
          "name": "conversion-type",
          "type": "string",
          "default": "",
          "usage": "Filter by conversion type: download, redownload, re-engagement",
          "allowed_values": [
            "download",
            "redownload",
            "re-engagement"
          ],
          "required": false
        },
        {
          "name": "country-code",
          "type": "string",
          "default": "",
          "usage": "Filter by install country code",
          "required": false
        },
        {
          "name": "did-win",
          "type": "string",
          "default": "",
          "usage": "Filter: 1=winning postbacks, 0=losing: 0, 1 (aliases: false=0, true=1)",
          "allowed_values": [
            "0",
            "1"
          ],
          "value_aliases": {
            "false": "0",
            "true": "1"
          },
          "required": false
        },
        {
          "name": "fidelity-type",
          "type": "string",
          "default": "",
          "usage": "Filter: 1=click-through, 0=view-through (both protocols; prefer --ad-interaction-type): 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "postback-sequence-index",
          "type": "string",
          "default": "",
          "usage": "Filter by conversion window: 0, 1, 2",
          "allowed_values": [
            "0",
            "1",
            "2"
          ],
          "required": false
        },
        {
          "name": "protocol",
          "type": "string",
          "default": "",
          "usage": "Filter by protocol: skadnetwork, adattributionkit (aliases: aak=adattributionkit, skan=skadnetwork)",
          "allowed_values": [
            "skadnetwork",
            "adattributionkit"
          ],
          "value_aliases": {
            "aak": "adattributionkit",
            "skan": "skadnetwork"
          },
          "required": false
        },
        {
          "name": "redownload",
          "type": "string",
          "default": "",
          "usage": "Filter: 1=redownloads, 0=first installs (both protocols; prefer --conversion-type): 0, 1 (aliases: false=0, true=1)",
          "allowed_values": [
            "0",
            "1"
          ],
          "value_aliases": {
            "false": "0",
            "true": "1"
          },
          "required": false
        },
        {
          "name": "registration-id",
          "type": "string",
          "default": "",
          "usage": "Filter by registration (from `p202 app list`)",
          "required": false
        },
        {
          "name": "registration-ids",
          "type": "string",
          "default": "",
          "usage": "Filter by several registrations, comma-separated",
          "required": false
        },
        {
          "name": "signature",
          "type": "string",
          "default": "",
          "usage": "Filter by verification state: valid, invalid, unverifiable, development",
          "allowed_values": [
            "valid",
            "invalid",
            "unverifiable",
            "development"
          ],
          "required": false
        },
        {
          "name": "source-identifier",
          "type": "string",
          "default": "",
          "usage": "Filter by SKAN 4 source identifier",
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Received-at range start (unix timestamp)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "Received-at range end (unix timestamp)",
          "required": false
        },
        {
          "name": "transaction-id",
          "type": "string",
          "default": "",
          "usage": "Filter by Apple transaction id",
          "required": false
        },
        {
          "name": "version",
          "type": "string",
          "default": "",
          "usage": "Filter by SKAN postback version (e.g. 4.0)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 app report",
      "use": "report",
      "short": "Cross-platform app report: iOS postbacks and Android installs, with the goals they reached",
      "long": "Reports Apple's postbacks by default (--platform ios, what this report meant before Android),\nAndroid installs with --platform android, and both with --platform all. Any platform groups by\nday (UTC), registration or platform; iOS also by ad-network, source, country, version, protocol\nor conversion-type (Apple's postbacks, decoded through `p202 app encoding`), Android also by\ncampaign, match-state, integrity-state, ctit-flag (click-to-install time: short, ok, long,\nunmeasured) or goal (the funnel: installs that reached each goal).\n\nEvery row carries platform, installs, the trust-class counts, goals_reached, revenue and\nevents. Headline figures count trusted signals only: signature-verified postbacks, attributed\ninstalls. --signature (iOS) or --trusted (Android) recompute them over one class.\nTotals are in meta.totals: per platform, and with both platforms {ios, android, combined}.\nAndroid figures are by install: a goal counts in its install's group.",
      "example": "p202 app report --platform all --group-by registration\n  p202 app report --platform android --group-by goal --registration-id 7\n  p202 app report --platform ios --group-by ad-network --signature valid",
      "runnable": true,
      "flags": [
        {
          "name": "ad-interaction-type",
          "type": "string",
          "default": "",
          "usage": "Filter: view (view-through) or click: view, click",
          "allowed_values": [
            "view",
            "click"
          ],
          "required": false
        },
        {
          "name": "ad-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by ad network id",
          "required": false
        },
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Android: only installs on this campaign's clicks (`p202 campaign list`)",
          "required": false
        },
        {
          "name": "app-id",
          "type": "string",
          "default": "",
          "usage": "Filter by the App Store id the postback itself named (forensic; prefer --registration-id)",
          "required": false
        },
        {
          "name": "campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by SKAN 2/3 campaign id",
          "required": false
        },
        {
          "name": "coarse-conversion-value",
          "type": "string",
          "default": "",
          "usage": "Filter by coarse value: low, medium, high",
          "allowed_values": [
            "low",
            "medium",
            "high"
          ],
          "required": false
        },
        {
          "name": "conversion-type",
          "type": "string",
          "default": "",
          "usage": "Filter by conversion type: download, redownload, re-engagement",
          "allowed_values": [
            "download",
            "redownload",
            "re-engagement"
          ],
          "required": false
        },
        {
          "name": "country-code",
          "type": "string",
          "default": "",
          "usage": "Filter by install country code",
          "required": false
        },
        {
          "name": "ctit-flag",
          "type": "string",
          "default": "",
          "usage": "Android: only installs whose click-to-install time is: short, ok, long, unmeasured",
          "allowed_values": [
            "short",
            "ok",
            "long",
            "unmeasured"
          ],
          "required": false
        },
        {
          "name": "did-win",
          "type": "string",
          "default": "",
          "usage": "Filter: 1=winning postbacks, 0=losing: 0, 1 (aliases: false=0, true=1)",
          "allowed_values": [
            "0",
            "1"
          ],
          "value_aliases": {
            "false": "0",
            "true": "1"
          },
          "required": false
        },
        {
          "name": "fast-goals",
          "type": "string",
          "default": "",
          "usage": "Android: only installs with a goal reached implausibly fast (1), or only those without one (0): 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "fidelity-type",
          "type": "string",
          "default": "",
          "usage": "Filter: 1=click-through, 0=view-through (both protocols; prefer --ad-interaction-type): 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "group-by",
          "type": "string",
          "default": "day",
          "usage": "Group by (ad-network, source, country, version, protocol, conversion-type need --platform ios; campaign, match-state, integrity-state, ctit-flag, goal need --platform android): day, registration, platform, ad-network, source, country, version, protocol, conversion-type, campaign, match-state, integrity-state, ctit-flag, goal",
          "allowed_values": [
            "day",
            "registration",
            "platform",
            "ad-network",
            "source",
            "country",
            "version",
            "protocol",
            "conversion-type",
            "campaign",
            "match-state",
            "integrity-state",
            "ctit-flag",
            "goal"
          ],
          "required": false
        },
        {
          "name": "integrity-state",
          "type": "string",
          "default": "",
          "usage": "Android: only installs whose Play Integrity verdict is in this state: not_requested, received, missing, pending, valid, invalid, error, skipped",
          "allowed_values": [
            "not_requested",
            "received",
            "missing",
            "pending",
            "valid",
            "invalid",
            "error",
            "skipped"
          ],
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max groups per platform (default 100)",
          "required": false
        },
        {
          "name": "match-state",
          "type": "string",
          "default": "",
          "usage": "Android: only installs in this match state: attributed, organic, third_party, unavailable, pending_click, bad_token, foreign_click, implausible, outside_window, duplicate_click, pending_integrity, integrity_failed, integrity_unverified",
          "allowed_values": [
            "attributed",
            "organic",
            "third_party",
            "unavailable",
            "pending_click",
            "bad_token",
            "foreign_click",
            "implausible",
            "outside_window",
            "duplicate_click",
            "pending_integrity",
            "integrity_failed",
            "integrity_unverified"
          ],
          "required": false
        },
        {
          "name": "platform",
          "type": "string",
          "default": "",
          "usage": "Platform (default ios; all reports both): ios, android, all",
          "allowed_values": [
            "ios",
            "android",
            "all"
          ],
          "required": false
        },
        {
          "name": "postback-sequence-index",
          "type": "string",
          "default": "",
          "usage": "Filter by conversion window: 0, 1, 2",
          "allowed_values": [
            "0",
            "1",
            "2"
          ],
          "required": false
        },
        {
          "name": "protocol",
          "type": "string",
          "default": "",
          "usage": "Filter by protocol: skadnetwork, adattributionkit (aliases: aak=adattributionkit, skan=skadnetwork)",
          "allowed_values": [
            "skadnetwork",
            "adattributionkit"
          ],
          "value_aliases": {
            "aak": "adattributionkit",
            "skan": "skadnetwork"
          },
          "required": false
        },
        {
          "name": "redownload",
          "type": "string",
          "default": "",
          "usage": "Filter: 1=redownloads, 0=first installs (both protocols; prefer --conversion-type): 0, 1 (aliases: false=0, true=1)",
          "allowed_values": [
            "0",
            "1"
          ],
          "value_aliases": {
            "false": "0",
            "true": "1"
          },
          "required": false
        },
        {
          "name": "registration-id",
          "type": "string",
          "default": "",
          "usage": "Filter by registration (from `p202 app list`)",
          "required": false
        },
        {
          "name": "registration-ids",
          "type": "string",
          "default": "",
          "usage": "Filter by several registrations, comma-separated",
          "required": false
        },
        {
          "name": "signature",
          "type": "string",
          "default": "",
          "usage": "Filter by verification state: valid, invalid, unverifiable, development",
          "allowed_values": [
            "valid",
            "invalid",
            "unverifiable",
            "development"
          ],
          "required": false
        },
        {
          "name": "source-identifier",
          "type": "string",
          "default": "",
          "usage": "Filter by SKAN 4 source identifier",
          "required": false
        },
        {
          "name": "test",
          "type": "string",
          "default": "",
          "usage": "Android: only test installs (1) or only real ones (0): 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Received-at range start (unix timestamp)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "Received-at range end (unix timestamp)",
          "required": false
        },
        {
          "name": "transaction-id",
          "type": "string",
          "default": "",
          "usage": "Filter by Apple transaction id",
          "required": false
        },
        {
          "name": "trusted",
          "type": "string",
          "default": "",
          "usage": "Android: only this trust class (trusted, refuted, unvouched); goals are then counted over it",
          "allowed_values": [
            "trusted",
            "refuted",
            "unvouched"
          ],
          "required": false
        },
        {
          "name": "version",
          "type": "string",
          "default": "",
          "usage": "Filter by SKAN postback version (e.g. 4.0)",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 app report",
          "ui_pages": [
            "Analyze › Mobile Apps"
          ],
          "phrases": [
            "app installs report",
            "skadnetwork postbacks"
          ]
        }
      ]
    },
    {
      "path": "p202 app rotate-token",
      "use": "rotate-token <id>",
      "short": "Replace the app token (the old token stops working immediately)",
      "long": "Mints a new app token for the registration and invalidates the old one — the\nremedy when builds should no longer reach the server with the token they shipped.\nThe token is an identifier, not a secret: it ships inside every copy of the app.",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 app schema",
      "use": "schema <registration-id>",
      "short": "Show the app's schema document exactly as devices fetch it",
      "long": "Reads the registration (for its app token), then fetches the public GET /apps/schema\nendpoint with it in the X-P202-App-Token header — the same request the SDK in the app\nmakes — so what you see is byte-for-byte what shipped builds receive.",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 app update",
      "use": "update <id>",
      "short": "Update a registered app's name, notes or test-signal policy (re-runs the postback claim)",
      "runnable": true,
      "flags": [
        {
          "name": "accept-test-signals",
          "type": "string",
          "default": "",
          "usage": "1 = trust test signals for this app (AdAttributionKit development-signed postbacks, Android test installs; integration testing), 0 = store them flagged (default): 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "app-name",
          "type": "string",
          "default": "",
          "usage": "Display name for reports",
          "required": false
        },
        {
          "name": "attribution-window-days",
          "type": "string",
          "default": "",
          "usage": "Android: days after its click an install may begin and still be attributed (1-365, default 7)",
          "required": false
        },
        {
          "name": "ctit-max-seconds",
          "type": "string",
          "default": "",
          "usage": "Android: flag an install that began later than this after its click (60-31536000, default 86400)",
          "required": false
        },
        {
          "name": "ctit-min-seconds",
          "type": "string",
          "default": "",
          "usage": "Android: flag an install that began sooner than this after its click (0-3600, default 10)",
          "required": false
        },
        {
          "name": "event-cap-per-minute",
          "type": "string",
          "default": "",
          "usage": "Android: events one install may post a minute; past it 429 (100-60000, default 200)",
          "required": false
        },
        {
          "name": "fast-goal-policy",
          "type": "string",
          "default": "",
          "usage": "Android: what a fast goal does, one of count, hold: count (pay it and flag it, default) or hold (flag it, never pay)",
          "allowed_values": [
            "count",
            "hold"
          ],
          "required": false
        },
        {
          "name": "fast-goal-seconds",
          "type": "string",
          "default": "",
          "usage": "Android: flag a goal reached sooner than this after its install (0-3600, default 5; 0 flags none)",
          "required": false
        },
        {
          "name": "install-cap-per-minute",
          "type": "string",
          "default": "",
          "usage": "Android: installs the app may report a minute; past it 429 (1-60000, default 300)",
          "required": false
        },
        {
          "name": "integrity-cloud-project-number",
          "type": "string",
          "default": "",
          "usage": "Android: the Google Cloud project NUMBER the SDK requests integrity tokens for (required for observe/require; can be replaced, not cleared)",
          "required": false
        },
        {
          "name": "integrity-mode",
          "type": "string",
          "default": "",
          "usage": "Android: Play Integrity mode, one of off, observe, require: off (default), observe (record verdicts) or require (attribute only a passing verdict); needs `app integrity credential set` first and --integrity-cloud-project-number",
          "allowed_values": [
            "off",
            "observe",
            "require"
          ],
          "required": false
        },
        {
          "name": "notes",
          "type": "string",
          "default": "",
          "usage": "Free-form notes",
          "required": false
        },
        {
          "name": "trust-client-revenue",
          "type": "string",
          "default": "",
          "usage": "Android: 1 = revenue the app reports may be paid by a goal valued from it; 0 = stored, never credited (default): 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        }
      ]
    },
    {
      "path": "p202 app verify",
      "use": "verify",
      "short": "Verify a postback payload's Apple signature (nothing is stored)",
      "long": "Reads a postback JSON object from --file (or piped stdin) and asks the server to\nverify Apple's signature. A body with a jws-string is verified as AdAttributionKit\n(the response decodes the JWS header and payload and names the signing key); anything\nelse as SKAdNetwork (the response carries the exact signed message, base64, for\ndiffing against another implementation). The verdict is valid / invalid /\nunverifiable / development.",
      "runnable": true,
      "flags": [
        {
          "name": "file",
          "shorthand": "f",
          "type": "string",
          "default": "",
          "usage": "Path to the postback JSON (default: read piped stdin)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 attribution",
      "use": "attribution",
      "short": "Multi-touch attribution: models, credit reports and journeys over your own clicks, plus platform-signed postbacks (SKAdNetwork, AdAttributionKit)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 attribution breakdown",
      "use": "breakdown",
      "short": "Attributed conversions, revenue, cost and ROI by a click dimension; --compare-model puts two models side by side",
      "long": "Attributed conversions (sum of credit) and revenue for conversions in the range, grouped by a\ndimension of the credited clicks; clicks and cost from the dimension's own clicks; and assisted\nconversions (journeys where the dimension had a touch before the converting click).\n\nWithout --model the report is \"effective\": each conversion under its campaign's model override\nwhen that model is active, otherwise the account default.\n\n--cohort click reads credits and assists by the date of the click they land on instead of the\nsale's date: each row is what its own clicks in the range earned (whenever they converted) against\ntheir cost, the population the classic reports count.",
      "runnable": true,
      "flags": [
        {
          "name": "cohort",
          "type": "string",
          "default": "",
          "usage": "conversion: the sales made in the range (default); click: what the range's clicks earned, as the classic reports count. Values: conversion, click",
          "allowed_values": [
            "conversion",
            "click"
          ],
          "required": false
        },
        {
          "name": "compare-model",
          "type": "string",
          "default": "",
          "usage": "A second model id, side by side",
          "required": false
        },
        {
          "name": "group-by",
          "type": "string",
          "default": "campaign",
          "usage": "Dimension: campaign, traffic_source, landing_page, keyword, c1, c2, c3, c4, country, device, day",
          "allowed_values": [
            "campaign",
            "traffic_source",
            "landing_page",
            "keyword",
            "c1",
            "c2",
            "c3",
            "c4",
            "country",
            "device",
            "day"
          ],
          "required": false
        },
        {
          "name": "keys",
          "type": "string",
          "default": "",
          "usage": "Only these rows: up to 1000 row keys (data[].key), comma-separated",
          "required": false
        },
        {
          "name": "limit",
          "type": "string",
          "default": "",
          "usage": "Rows, 1-1000 (default 100)",
          "required": false
        },
        {
          "name": "model",
          "type": "string",
          "default": "",
          "usage": "Model id (default: each campaign's override, else the account default)",
          "required": false
        },
        {
          "name": "offset",
          "type": "string",
          "default": "",
          "usage": "Rows to skip, for paging past --limit (meta.groups is the total; needs a server with attribution paging)",
          "required": false
        },
        {
          "name": "period",
          "type": "string",
          "default": "",
          "usage": "Range (default: the last 30 days): today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Range start, unix seconds",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "Range end, unix seconds",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 attribution breakdown",
          "ui_pages": [
            "Attribution"
          ],
          "phrases": [
            "multi touch attribution",
            "attribution report"
          ]
        }
      ]
    },
    {
      "path": "p202 attribution export",
      "use": "export",
      "short": "Attribution exports: a breakdown written to CSV by the export runner, downloadable and optionally sent to an https webhook",
      "long": "An export is a job: the export runner (the minutely cron) builds the breakdown it names,\nwrites every group to a CSV file, and, when the export has a webhook, POSTs the file there,\nsigned with HMAC-SHA256 (X-P202-Signature: sha256=<hex> over \"<X-P202-Timestamp>.<body>\").\n\nWebhooks go to https URLs on public addresses only: every address the host resolves to is\nchecked, the connection is pinned to the checked address, and redirects are not followed.",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 attribution export create",
      "use": "create",
      "short": "Queue an export of a breakdown: now, or at --run-at; optionally to a signed https webhook",
      "long": "Queue an export. Without --model it exports the account default model (stored as its id, so\nthe job reads a fixed model); without a range, the last 30 days. The response carries\nwebhook_secret once when the export has a webhook: keep it with the receiver.",
      "runnable": true,
      "flags": [
        {
          "name": "compare-model",
          "type": "string",
          "default": "",
          "usage": "A second model id, side by side",
          "required": false
        },
        {
          "name": "group-by",
          "type": "string",
          "default": "campaign",
          "usage": "Dimension: campaign, traffic_source, landing_page, keyword, c1, c2, c3, c4, country, device, day",
          "allowed_values": [
            "campaign",
            "traffic_source",
            "landing_page",
            "keyword",
            "c1",
            "c2",
            "c3",
            "c4",
            "country",
            "device",
            "day"
          ],
          "required": false
        },
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        },
        {
          "name": "model",
          "type": "string",
          "default": "",
          "usage": "Model id (default: the account default model)",
          "required": false
        },
        {
          "name": "period",
          "type": "string",
          "default": "",
          "usage": "Range (default: the last 30 days): today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "run-at",
          "type": "string",
          "default": "",
          "usage": "When to run it, unix seconds (default: the next export run, within a minute)",
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Range start, unix seconds",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "Range end, unix seconds",
          "required": false
        },
        {
          "name": "webhook-secret",
          "type": "string",
          "default": "",
          "usage": "HMAC secret for the webhook signature, 16-255 characters (default: generated and returned once)",
          "required": false
        },
        {
          "name": "webhook-url",
          "type": "string",
          "default": "",
          "usage": "Also POST the CSV here: https, public address, no redirects",
          "required": false
        }
      ]
    },
    {
      "path": "p202 attribution export delete",
      "use": "delete <id>",
      "short": "Delete an export and its file (not while it is running); supports --ids for bulk",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated export IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 attribution export download",
      "use": "download <id>",
      "short": "Download an export's CSV to --output, or to stdout",
      "runnable": true,
      "flags": [
        {
          "name": "output",
          "shorthand": "O",
          "type": "string",
          "default": "",
          "usage": "Write the CSV to this file instead of stdout",
          "required": false
        }
      ]
    },
    {
      "path": "p202 attribution export get",
      "use": "get <id>",
      "short": "One export: its status, rows, webhook answer and last error",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 attribution export list",
      "use": "list",
      "short": "List exports, newest first",
      "runnable": true,
      "flags": [
        {
          "name": "limit",
          "type": "int",
          "default": "50",
          "usage": "Rows, 1-200",
          "required": false
        },
        {
          "name": "status",
          "type": "string",
          "default": "",
          "usage": "Only this status: pending, running, completed, failed",
          "allowed_values": [
            "pending",
            "running",
            "completed",
            "failed"
          ],
          "required": false
        }
      ]
    },
    {
      "path": "p202 attribution export retry",
      "use": "retry <id>",
      "short": "Queue a failed export again, with its attempts reset",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 attribution journey",
      "use": "journey <conv_id>",
      "short": "One conversion's journey: its touches, the identity signals that linked them, and every model's credit",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 attribution journeys",
      "use": "journeys",
      "short": "Journey metrics: length distribution, time to convert, one-touch share by browser",
      "runnable": true,
      "flags": [
        {
          "name": "period",
          "type": "string",
          "default": "",
          "usage": "Range (default: the last 30 days): today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Range start, unix seconds",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "Range end, unix seconds",
          "required": false
        }
      ]
    },
    {
      "path": "p202 attribution model",
      "use": "model",
      "short": "Manage attribution models (every account has one default; credits are computed for every active model)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 attribution model create",
      "use": "create",
      "short": "Create an attribution model; its credits are computed for existing conversions by the next worker run",
      "runnable": true,
      "flags": [
        {
          "name": "default",
          "type": "bool",
          "default": "false",
          "usage": "Make this the account default model",
          "required": false
        },
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        },
        {
          "name": "lookback-days",
          "type": "int",
          "default": "30",
          "usage": "Days before a conversion whose clicks can earn credit, 1-365",
          "required": false
        },
        {
          "name": "model-name",
          "type": "string",
          "default": "",
          "usage": "Model name (required)",
          "required": true
        },
        {
          "name": "model-type",
          "type": "string",
          "default": "",
          "usage": "Type (required): last_touch, first_touch, linear, time_decay, position_based",
          "allowed_values": [
            "last_touch",
            "first_touch",
            "linear",
            "time_decay",
            "position_based"
          ],
          "required": true
        },
        {
          "name": "status",
          "type": "string",
          "default": "",
          "usage": "Status: active, inactive",
          "allowed_values": [
            "active",
            "inactive"
          ],
          "required": false
        },
        {
          "name": "weighting-config",
          "type": "string",
          "default": "",
          "usage": "Weighting config JSON object: time_decay {\"half_life_hours\":48}, position_based {\"first_weight\":0.4,\"last_weight\":0.4}",
          "required": false
        }
      ]
    },
    {
      "path": "p202 attribution model delete",
      "use": "delete <id>",
      "short": "Delete an attribution model and its credits (not the default); supports --ids for bulk",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated model IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 attribution model get",
      "use": "get <id>",
      "short": "Get an attribution model",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 attribution model list",
      "use": "list",
      "short": "List attribution models",
      "runnable": true,
      "flags": [
        {
          "name": "type",
          "shorthand": "t",
          "type": "string",
          "default": "",
          "usage": "Filter by type: last_touch, first_touch, linear, time_decay, position_based",
          "allowed_values": [
            "last_touch",
            "first_touch",
            "linear",
            "time_decay",
            "position_based"
          ],
          "required": false
        }
      ]
    },
    {
      "path": "p202 attribution model update",
      "use": "update <id>",
      "short": "Update an attribution model (changing its type resets its weighting config to that type's defaults)",
      "runnable": true,
      "flags": [
        {
          "name": "default",
          "type": "bool",
          "default": "false",
          "usage": "Make this the account default model",
          "required": false
        },
        {
          "name": "lookback-days",
          "type": "int",
          "default": "30",
          "usage": "Days before a conversion whose clicks can earn credit, 1-365",
          "required": false
        },
        {
          "name": "model-name",
          "type": "string",
          "default": "",
          "usage": "Model name",
          "required": false
        },
        {
          "name": "model-type",
          "type": "string",
          "default": "",
          "usage": "Type: last_touch, first_touch, linear, time_decay, position_based",
          "allowed_values": [
            "last_touch",
            "first_touch",
            "linear",
            "time_decay",
            "position_based"
          ],
          "required": false
        },
        {
          "name": "status",
          "type": "string",
          "default": "",
          "usage": "Status: active, inactive",
          "allowed_values": [
            "active",
            "inactive"
          ],
          "required": false
        },
        {
          "name": "weighting-config",
          "type": "string",
          "default": "",
          "usage": "Weighting config JSON object: time_decay {\"half_life_hours\":48}, position_based {\"first_weight\":0.4,\"last_weight\":0.4}",
          "required": false
        }
      ]
    },
    {
      "path": "p202 attribution queue",
      "use": "queue",
      "short": "The attribution worker's backlog: conversions waiting, failing (with the error), and why each was queued",
      "runnable": true,
      "flags": [
        {
          "name": "limit",
          "type": "int",
          "default": "50",
          "usage": "Rows of the backlog to list, 1-500",
          "required": false
        }
      ]
    },
    {
      "path": "p202 campaign",
      "use": "campaign",
      "short": "Manage campaigns (affiliate offers with URLs, payouts, and postback settings)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 campaign check-urls",
      "use": "check-urls",
      "short": "Find offer URLs whose host is dead, without sending clicks",
      "long": "Checks campaign offer URL slots (aff_campaign_url, _2 to _5) and reports which\npoint at a host that no longer works. Opening an affiliate link registers a\nclick, so by default no HTTP request is sent: each unique host is resolved\n(DNS), connected to (TCP) and, for https, put through a TLS handshake with\nnormal certificate verification, then the connection is closed.\n\nstatus per URL: ok, invalid_url, dns_failed, connect_failed, timeout,\ntls_failed (and http_failed with --http); detail says why.\n\n--http also sends one HEAD request per unique URL (GET only if HEAD answers\n405), follows no redirect, and reports http_status and location. Affiliate\nnetworks may count these as clicks, so it asks first (--force skips).\nTokens such as [[subid]] are sent as \"p202check\".\n\nLike `p202 rotator check`, it exits 5 (partial_failure) when any URL's\nstatus is not ok; every row is still printed on stdout.",
      "example": "p202 campaign check-urls\n  p202 campaign check-urls --url-contains g2afse.com --slot 1 --timeout 10s\n  p202 campaign check-urls --ids 279,281 --json",
      "runnable": true,
      "flags": [
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Only campaigns in this affiliate network (ids from p202 aff-network list)",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip the --http confirmation prompt",
          "required": false
        },
        {
          "name": "http",
          "type": "bool",
          "default": "false",
          "usage": "Also send a HEAD request per URL and report its status; affiliate networks may count it as a click",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Only these campaign IDs (comma-separated)",
          "required": false
        },
        {
          "name": "slot",
          "type": "string",
          "default": "all",
          "usage": "URL slots to check: 1-5, comma-separated, or all",
          "required": false
        },
        {
          "name": "timeout",
          "type": "duration",
          "default": "5s",
          "usage": "Time allowed per host for DNS, connect and TLS together (and per --http request)",
          "required": false
        },
        {
          "name": "url-contains",
          "type": "string",
          "default": "",
          "usage": "Only offer URLs containing this text (case-insensitive)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 campaign clone",
      "use": "clone <id>",
      "short": "Clone a campaign",
      "runnable": true,
      "flags": [
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        },
        {
          "name": "name",
          "type": "string",
          "default": "",
          "usage": "Optional name override for the cloned campaign",
          "required": false
        }
      ]
    },
    {
      "path": "p202 campaign create",
      "use": "create",
      "short": "Create a new campaign",
      "example": "p202 campaign create --aff-campaign-name <campaign_name> --aff-campaign-url <campaign_url> --aff-campaign-payout <campaign_payout> --aff-network-id <id from p202 aff-network list> --json",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-cloaking",
          "type": "string",
          "default": "",
          "usage": "Enable cloaking (1) or not (0): 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "aff-campaign-currency",
          "type": "string",
          "default": "",
          "usage": "Currency code (e.g. USD)",
          "required": false
        },
        {
          "name": "aff-campaign-foreign-payout",
          "type": "string",
          "default": "",
          "usage": "Foreign currency payout",
          "required": false
        },
        {
          "name": "aff-campaign-name",
          "type": "string",
          "default": "",
          "usage": "Campaign name (required)",
          "required": true
        },
        {
          "name": "aff-campaign-payout",
          "type": "string",
          "default": "",
          "usage": "Default payout (required)",
          "required": true
        },
        {
          "name": "aff-campaign-rotate",
          "type": "string",
          "default": "",
          "usage": "Enable rotation (1) or not (0): 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "aff-campaign-url",
          "type": "string",
          "default": "",
          "usage": "Primary offer URL (required)",
          "required": true
        },
        {
          "name": "aff-campaign-url-2",
          "type": "string",
          "default": "",
          "usage": "Offer URL 2 (used with --aff-campaign-rotate 1)",
          "required": false
        },
        {
          "name": "aff-campaign-url-3",
          "type": "string",
          "default": "",
          "usage": "Offer URL 3",
          "required": false
        },
        {
          "name": "aff-campaign-url-4",
          "type": "string",
          "default": "",
          "usage": "Offer URL 4",
          "required": false
        },
        {
          "name": "aff-campaign-url-5",
          "type": "string",
          "default": "",
          "usage": "Offer URL 5",
          "required": false
        },
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Category (affiliate network) id, from `p202 aff-network list` (required)",
          "required": true
        },
        {
          "name": "app-registration-id",
          "type": "string",
          "default": "",
          "usage": "The Android app registration this campaign's store links install (`p202 app list --platform android`; 0 unlinks). An install of another app on its click is foreign_click",
          "required": false
        },
        {
          "name": "attribution-model-id",
          "type": "string",
          "default": "",
          "usage": "The attribution model this campaign's conversions are credited with, overriding the account default (`p202 attribution model list`; 0 returns it to the default)",
          "required": false
        },
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        },
        {
          "name": "identity-signals",
          "type": "string",
          "default": "",
          "usage": "Link this campaign's clicks into multi-touch journeys (1, default) or not (0): 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "payout-mode",
          "type": "string",
          "default": "",
          "usage": "How conversions set a click's value, replace (latest payout, default) or accumulate (sum): replace, accumulate",
          "allowed_values": [
            "replace",
            "accumulate"
          ],
          "required": false
        }
      ]
    },
    {
      "path": "p202 campaign delete",
      "use": "delete <id>",
      "short": "Delete a campaign",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated campaign IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 campaign get",
      "use": "get <id>",
      "short": "Get a campaign by ID",
      "long": "Get a campaign by id. Accepts the internal aff_campaign_id (from `campaign list`). If you pass the\npublic aff_campaign_id_public (the value in tracking links / the UI), it is resolved automatically;\nuse --public to force the public lookup.",
      "runnable": true,
      "flags": [
        {
          "name": "public",
          "type": "bool",
          "default": "false",
          "usage": "Treat the id as the public aff_campaign_id_public",
          "required": false
        }
      ]
    },
    {
      "path": "p202 campaign list",
      "use": "list",
      "short": "List campaigns (affiliate offers with URLs, payouts, and postback settings)",
      "runnable": true,
      "flags": [
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by affiliate network ID (from `p202 aff-network list`)",
          "required": false
        },
        {
          "name": "all",
          "type": "bool",
          "default": "false",
          "usage": "Fetch all rows across pages",
          "required": false
        },
        {
          "name": "days",
          "type": "int",
          "default": "0",
          "usage": "Stats window for --with-stats in days, ending now (ignored when --period is given)",
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "min-clicks",
          "type": "int",
          "default": "0",
          "usage": "With --with-stats: only campaigns with at least N clicks in the window (searches every page)",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "page",
          "type": "string",
          "default": "",
          "usage": "Page number",
          "required": false
        },
        {
          "name": "period",
          "type": "string",
          "default": "",
          "usage": "Stats window for --with-stats (default last30): today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "resolve-names",
          "type": "bool",
          "default": "false",
          "usage": "Resolve foreign key IDs to names",
          "required": false
        },
        {
          "name": "url-contains",
          "type": "string",
          "default": "",
          "usage": "Only campaigns with a URL containing this text (case-insensitive; searches every page; fields: aff_campaign_url, aff_campaign_url_2, aff_campaign_url_3, aff_campaign_url_4, aff_campaign_url_5)",
          "required": false
        },
        {
          "name": "with-stats",
          "type": "bool",
          "default": "false",
          "usage": "Add each campaign's traffic in the window: total_clicks, total_leads, total_income, total_cost, total_net (0 when none; needs the reports:read scope)",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 campaign list",
          "ui_pages": [
            "Setup › Campaigns"
          ],
          "phrases": [
            "affiliate offers",
            "my offers"
          ]
        }
      ]
    },
    {
      "path": "p202 campaign optimize",
      "use": "optimize <campaign_id>",
      "short": "Diagnose a campaign and recommend a salvage offer for its traffic",
      "long": "Summarizes the campaign's break-even/ROI status and ranks other offers by EPC,\nso you can route losing traffic to the offer that monetizes it best.",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by INTERNAL campaign id (from `campaign list`), not the public id in tracking URLs",
          "required": false
        },
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by affiliate network ID",
          "required": false
        },
        {
          "name": "browser-id",
          "type": "string",
          "default": "",
          "usage": "Filter by browser ID (the id of a `--breakdown browser` row)",
          "required": false
        },
        {
          "name": "country-id",
          "type": "string",
          "default": "",
          "usage": "Filter by country ID",
          "required": false
        },
        {
          "name": "device-type",
          "type": "string",
          "default": "",
          "usage": "Filter by device type ID: 1 Desktop, 2 Mobile, 3 Tablet, 4 Bot (the ids of `--breakdown device_type` rows)",
          "required": false
        },
        {
          "name": "ip",
          "type": "string",
          "default": "",
          "usage": "Only clicks from this one IP address, IPv4 or IPv6",
          "required": false
        },
        {
          "name": "isp-id",
          "type": "string",
          "default": "",
          "usage": "Filter by ISP/carrier ID (the id of a `--breakdown isp` row)",
          "required": false
        },
        {
          "name": "keyword",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose keyword contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Filter by landing page ID",
          "required": false
        },
        {
          "name": "method-of-promotion",
          "type": "string",
          "default": "",
          "usage": "Only direct-link clicks or only landing-page clicks: directlink, landingpage",
          "allowed_values": [
            "directlink",
            "landingpage"
          ],
          "required": false
        },
        {
          "name": "period",
          "shorthand": "p",
          "type": "string",
          "default": "",
          "usage": "Period: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "platform-id",
          "type": "string",
          "default": "",
          "usage": "Filter by platform (OS) ID (the id of a `--breakdown platform` row)",
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC account ID",
          "required": false
        },
        {
          "name": "ppc-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC network ID, or none for the clicks with no traffic source",
          "required": false
        },
        {
          "name": "referer",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose referring URL contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "region-id",
          "type": "string",
          "default": "",
          "usage": "Filter by region ID (the id of a `--breakdown region` row)",
          "required": false
        },
        {
          "name": "show",
          "type": "string",
          "default": "",
          "usage": "Which clicks count (default all): all, real, filtered, filtered_bot, leads; real = not filtered, filtered_bot = filtered as bots, leads = converted",
          "allowed_values": [
            "all",
            "real",
            "filtered",
            "filtered_bot",
            "leads"
          ],
          "required": false
        },
        {
          "name": "text-ad-id",
          "type": "string",
          "default": "",
          "usage": "Filter by text ad ID",
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "End, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
          "required": false
        }
      ]
    },
    {
      "path": "p202 campaign replace-url",
      "use": "replace-url",
      "short": "Find campaigns whose offer URLs contain a string and rewrite those URLs in bulk",
      "long": "Finds every campaign whose offer URL slots (aff_campaign_url, _2 to _5)\ncontain --match (case-insensitive), and rewrites the matching slots:\n\n  --with <text>  replaces the matched text inside the URL\n  --set <url>    replaces the whole URL; {id} and {slug} (the campaign\n                 name, lowercased and hyphenated) are filled per campaign\n\nRun with --dry-run first: it lists every campaign, slot, old and new URL\nand writes nothing. Without --dry-run the same list is shown and you are\nasked to confirm (--force skips the prompt; --staged records one proposal\nper campaign instead of writing). Matching runs in the CLI over every page\nof campaigns, so it works against any server version.\n\nRe-running is safe with --set (updated URLs no longer contain --match),\nbut with --with it rewrites again if the replacement still contains --match.\n\nUndo: every run that applies a change saves the applied slots (old and new\nURL, profile, base URL) to ~/.p202/undo/replace-url-<UTC time>.json and\nprints `Undo with: p202 campaign replace-url --undo <file>` (under --json\nalso meta.undo_manifest). --undo puts old_url back only where the slot\nstill holds that run's new_url; slots changed since, and deleted campaigns,\nare left alone and listed with status skipped. It refuses a manifest\nwritten against another base URL, cannot be combined with --match, --with,\n--set, --slot, --ids or --aff-network-id, and otherwise behaves like a\nnormal run (--dry-run, the prompt, --force, --staged, exit 5 on a failed\nPUT). An undo that applies changes saves its own manifest, so it can be\nundone too. If a manifest cannot be saved after the writes, the command\nprints it on stderr and exits 5.",
      "example": "p202 campaign replace-url --match g2afse.com --set 'https://example.com/?utm_source={slug}' --dry-run\n  p202 campaign replace-url --match http://promo.example.com --with https://promo.example.com --force\n  p202 campaign replace-url --undo ~/.p202/undo/replace-url-20260930T101500Z.json --dry-run",
      "runnable": true,
      "flags": [
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Only campaigns in this affiliate network (`p202 aff-network list`)",
          "required": false
        },
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "List the changes without writing anything",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip the confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Only these campaign IDs (comma-separated)",
          "required": false
        },
        {
          "name": "match",
          "type": "string",
          "default": "",
          "usage": "Text the offer URLs to change contain (case-insensitive; required unless --undo)",
          "required": false
        },
        {
          "name": "set",
          "type": "string",
          "default": "",
          "usage": "Replace the whole URL with this; {id} and {slug} are filled per campaign",
          "required": false
        },
        {
          "name": "slot",
          "type": "string",
          "default": "all",
          "usage": "URL slots to consider: 1-5, comma-separated, or all",
          "required": false
        },
        {
          "name": "undo",
          "type": "string",
          "default": "",
          "usage": "Revert a run from its undo manifest `file` (printed after \"Undo with:\"): restores old URLs where the slot is unchanged since",
          "required": false
        },
        {
          "name": "with",
          "type": "string",
          "default": "",
          "usage": "Replace the matched text with this",
          "required": false
        }
      ]
    },
    {
      "path": "p202 campaign update",
      "use": "update <id>",
      "short": "Update a campaign",
      "example": "p202 campaign update <id from p202 campaign list> --aff-campaign-name <new value> --json\n  (only the flags given are sent; the rest of the campaign is unchanged)",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-cloaking",
          "type": "string",
          "default": "",
          "usage": "Enable cloaking (1) or not (0): 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "aff-campaign-currency",
          "type": "string",
          "default": "",
          "usage": "Currency code (e.g. USD)",
          "required": false
        },
        {
          "name": "aff-campaign-foreign-payout",
          "type": "string",
          "default": "",
          "usage": "Foreign currency payout",
          "required": false
        },
        {
          "name": "aff-campaign-name",
          "type": "string",
          "default": "",
          "usage": "Campaign name",
          "required": false
        },
        {
          "name": "aff-campaign-payout",
          "type": "string",
          "default": "",
          "usage": "Default payout",
          "required": false
        },
        {
          "name": "aff-campaign-rotate",
          "type": "string",
          "default": "",
          "usage": "Enable rotation (1) or not (0): 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "aff-campaign-url",
          "type": "string",
          "default": "",
          "usage": "Primary offer URL",
          "required": false
        },
        {
          "name": "aff-campaign-url-2",
          "type": "string",
          "default": "",
          "usage": "Offer URL 2 (used with --aff-campaign-rotate 1) (\"\" clears it)",
          "required": false
        },
        {
          "name": "aff-campaign-url-3",
          "type": "string",
          "default": "",
          "usage": "Offer URL 3 (\"\" clears it)",
          "required": false
        },
        {
          "name": "aff-campaign-url-4",
          "type": "string",
          "default": "",
          "usage": "Offer URL 4 (\"\" clears it)",
          "required": false
        },
        {
          "name": "aff-campaign-url-5",
          "type": "string",
          "default": "",
          "usage": "Offer URL 5 (\"\" clears it)",
          "required": false
        },
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Category (affiliate network) id, from `p202 aff-network list`",
          "required": false
        },
        {
          "name": "app-registration-id",
          "type": "string",
          "default": "",
          "usage": "The Android app registration this campaign's store links install (`p202 app list --platform android`; 0 unlinks). An install of another app on its click is foreign_click",
          "required": false
        },
        {
          "name": "attribution-model-id",
          "type": "string",
          "default": "",
          "usage": "The attribution model this campaign's conversions are credited with, overriding the account default (`p202 attribution model list`; 0 returns it to the default)",
          "required": false
        },
        {
          "name": "identity-signals",
          "type": "string",
          "default": "",
          "usage": "Link this campaign's clicks into multi-touch journeys (1, default) or not (0): 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "payout-mode",
          "type": "string",
          "default": "",
          "usage": "How conversions set a click's value, replace (latest payout, default) or accumulate (sum): replace, accumulate",
          "allowed_values": [
            "replace",
            "accumulate"
          ],
          "required": false
        }
      ]
    },
    {
      "path": "p202 change",
      "use": "change",
      "short": "Review and resolve staged writes (proposals recorded by --staged)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 change apply",
      "use": "apply <change_id>",
      "short": "Apply a staged change (performs the recorded write)",
      "long": "Apply a staged change. This performs the recorded write, re-validated on the\nserver against current state and this key's authorization — a propose-only\n(`stage`-scoped) key cannot apply; the applier needs the write scope for the\narea the change touches. Running apply IS the approval, so it confirms\ninteractively unless --force is passed.",
      "runnable": true,
      "flags": [
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        }
      ]
    },
    {
      "path": "p202 change discard",
      "use": "discard <change_id>",
      "short": "Discard a staged change without performing it",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 change list",
      "use": "list",
      "short": "List staged changes (yours; --all for every user's, admin only)",
      "runnable": true,
      "flags": [
        {
          "name": "all",
          "type": "bool",
          "default": "false",
          "usage": "Every user's changes, not just yours (admin only)",
          "required": false
        },
        {
          "name": "status",
          "type": "string",
          "default": "",
          "usage": "Filter by status: staged, applying, applied, discarded, apply_interrupted",
          "allowed_values": [
            "staged",
            "applying",
            "applied",
            "discarded",
            "apply_interrupted"
          ],
          "required": false
        }
      ]
    },
    {
      "path": "p202 change show",
      "use": "show <change_id>",
      "short": "Show one staged change, including its payload and preview",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 click",
      "use": "click",
      "short": "View tracked clicks (inbound visitor events from traffic sources), and set what past clicks cost",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 click conversions",
      "use": "conversions <click-id>",
      "short": "Explain a click's value: every conversion on it, whether it counts, and why not",
      "long": "Lists every conversion recorded on the click — counted, unpaid, superseded,\ndeleted and reversals alike — with its amount, what produced it (source), what\nthat is (a goal and version, an upload, the conversion a reversal nets, the API\nkey that wrote it), its transaction id, and whether it counts toward the\nclick's value, with the reason when it does not.\n\nThe table shows one line per conversion and ends with the click's value; --json\nand --ndjson return the API's rows unchanged, and --json adds the \"click\"\nsummary (value, payout mode, whether the rows add up to what the reports show).",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 click get",
      "use": "get <id>",
      "short": "Get a click by ID",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 click list",
      "use": "list",
      "short": "List tracked clicks with optional filters by campaign, time range, or bot status",
      "long": "Lists clicks newest first, with what the Visitors page shows for each: campaign,\ntraffic source, keyword, IP, location, device, referrer and landing URLs. It takes\nthe Visitors page's filters, as `p202 report` does: --keyword and --referer\n(contains), --ip, --device-type, --show real|filtered|filtered_bot|leads, location,\nbrowser and platform ids, and --period.\n\n--follow is the Spy page: it prints the newest --limit clicks (default 10), then\neach new click as it arrives, polling every --interval, until interrupted or\n--stop-after elapses. Under --json or --ndjson it writes one JSON object per\nclick per line.\n\n  p202 click list --aff-campaign-id 12 --time-from 2026-10-01 --all --csv\n  p202 click list --keyword shoes --show real --period last7\n  p202 click list --follow --ndjson --stop-after 10m",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by INTERNAL campaign id (from `campaign list`), not the public id in tracking URLs",
          "required": false
        },
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by affiliate network ID",
          "required": false
        },
        {
          "name": "all",
          "type": "bool",
          "default": "false",
          "usage": "Fetch all rows across pages",
          "required": false
        },
        {
          "name": "browser-id",
          "type": "string",
          "default": "",
          "usage": "Filter by browser ID (the id of a `--breakdown browser` row)",
          "required": false
        },
        {
          "name": "click-bot",
          "type": "string",
          "default": "",
          "usage": "Filter: 0=human, 1=bot: 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "click-lead",
          "type": "string",
          "default": "",
          "usage": "Filter: 0=clicks only, 1=conversions only: 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "country-id",
          "type": "string",
          "default": "",
          "usage": "Filter by country ID",
          "required": false
        },
        {
          "name": "device-type",
          "type": "string",
          "default": "",
          "usage": "Filter by device type ID: 1 Desktop, 2 Mobile, 3 Tablet, 4 Bot (the ids of `--breakdown device_type` rows)",
          "required": false
        },
        {
          "name": "follow",
          "type": "bool",
          "default": "false",
          "usage": "Keep printing new clicks as they arrive (the Spy page)",
          "required": false
        },
        {
          "name": "interval",
          "type": "duration",
          "default": "5s",
          "usage": "With --follow: how often to poll (at least 1s)",
          "required": false
        },
        {
          "name": "ip",
          "type": "string",
          "default": "",
          "usage": "Only clicks from this one IP address, IPv4 or IPv6",
          "required": false
        },
        {
          "name": "isp-id",
          "type": "string",
          "default": "",
          "usage": "Filter by ISP/carrier ID (the id of a `--breakdown isp` row)",
          "required": false
        },
        {
          "name": "keyword",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose keyword contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Filter by landing page ID",
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "method-of-promotion",
          "type": "string",
          "default": "",
          "usage": "Only direct-link clicks or only landing-page clicks: directlink, landingpage",
          "allowed_values": [
            "directlink",
            "landingpage"
          ],
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "page",
          "type": "string",
          "default": "",
          "usage": "Page number (maps to offset)",
          "required": false
        },
        {
          "name": "period",
          "shorthand": "p",
          "type": "string",
          "default": "",
          "usage": "Period: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "platform-id",
          "type": "string",
          "default": "",
          "usage": "Filter by platform (OS) ID (the id of a `--breakdown platform` row)",
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC account ID",
          "required": false
        },
        {
          "name": "ppc-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC network ID, or none for the clicks with no traffic source",
          "required": false
        },
        {
          "name": "referer",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose referring URL contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "region-id",
          "type": "string",
          "default": "",
          "usage": "Filter by region ID (the id of a `--breakdown region` row)",
          "required": false
        },
        {
          "name": "show",
          "type": "string",
          "default": "",
          "usage": "Which clicks count (default all): all, real, filtered, filtered_bot, leads; real = not filtered, filtered_bot = filtered as bots, leads = converted",
          "allowed_values": [
            "all",
            "real",
            "filtered",
            "filtered_bot",
            "leads"
          ],
          "required": false
        },
        {
          "name": "stop-after",
          "type": "duration",
          "default": "0s",
          "usage": "With --follow: stop after this long, e.g. 10m (0 follows until interrupted)",
          "required": false
        },
        {
          "name": "text-ad-id",
          "type": "string",
          "default": "",
          "usage": "Filter by text ad ID",
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "End, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 click list --follow",
          "ui_pages": [
            "Spy"
          ],
          "phrases": [
            "realtime traffic",
            "realtime clicks",
            "live traffic",
            "live clicks",
            "watch clicks",
            "watch traffic",
            "tail clicks",
            "stream clicks",
            "monitor traffic",
            "clicks as they arrive",
            "clicks as they come in",
            "incoming clicks"
          ]
        },
        {
          "run": "p202 click list",
          "ui_pages": [
            "Visitors"
          ],
          "phrases": [
            "visitor log",
            "recent clicks",
            "click history",
            "individual clicks"
          ]
        }
      ]
    },
    {
      "path": "p202 click update-cpc",
      "use": "update-cpc",
      "short": "Set what a set of past clicks cost (the UI's Update CPC), after counting them",
      "long": "Sets the cost (CPC) of the account's clicks between --from 00:00:00 and --to 23:59:59 in\nthe account's time zone, narrowed by any of the id filters and --method-of-promotion.\n\nIt counts the clicks first (POST /clicks/cpc?dry_run=1) and says how many, then asks\n(--force skips the question; --dry-run stops after the count). The update carries the\ncount and the highest click id it saw, and the server writes only if those clicks still\nnumber the same — so a click recorded after the count is never changed, and when the\nselection moved nothing is written (exit 1; run the command again).\n\nNeeds a role with access_to_update_section and a key with clicks:write. Cannot be staged.\nReports show the new cost once the data engine rebuilds the hours (its cron job).",
      "example": "p202 click update-cpc --from 2026-10-01 --to 2026-10-07 --cpc 0.25 --aff-campaign-id 12 --dry-run\n  p202 click update-cpc --from 2026-10-07 --to 2026-10-07 --cpc 0.00125 --ppc-account-id 3\n  p202 click update-cpc --from 2026-10-01 --to 2026-10-31 --cpc 1.10 --method-of-promotion directlink --force",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Only this campaign's clicks (id from `p202 campaign list`; 0 = every campaign)",
          "required": false
        },
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Only this category's clicks (id from `p202 aff-network list`; 0 = every category)",
          "required": false
        },
        {
          "name": "cpc",
          "type": "string",
          "default": "",
          "usage": "What each click cost, in dollars, up to 99.99999 with five decimals (required)",
          "required": true
        },
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Count the clicks and write nothing",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Update without asking (the count is still checked)",
          "required": false
        },
        {
          "name": "from",
          "type": "string",
          "default": "",
          "usage": "First day, YYYY-MM-DD, in the account's time zone (required)",
          "required": true
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Only this landing page's clicks (id from `p202 landing-page list`; 0 = every landing page)",
          "required": false
        },
        {
          "name": "method-of-promotion",
          "type": "string",
          "default": "",
          "usage": "Only direct-link or only landing-page clicks (default: both): directlink, landingpage",
          "allowed_values": [
            "directlink",
            "landingpage"
          ],
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "Only this traffic source account's clicks (id from `p202 ppc-account list`; 0 = every traffic source account)",
          "required": false
        },
        {
          "name": "ppc-network-id",
          "type": "string",
          "default": "",
          "usage": "Only this traffic source's clicks (id from `p202 ppc-network list`; 0 = every traffic source)",
          "required": false
        },
        {
          "name": "text-ad-id",
          "type": "string",
          "default": "",
          "usage": "Only this text ad's clicks (id from `p202 text-ad list`; 0 = every text ad)",
          "required": false
        },
        {
          "name": "to",
          "type": "string",
          "default": "",
          "usage": "Last day, YYYY-MM-DD, in the account's time zone (required)",
          "required": true
        }
      ],
      "tasks": [
        {
          "run": "p202 click update-cpc",
          "ui_pages": [
            "Update › Update CPC"
          ],
          "phrases": [
            "set what clicks cost",
            "record click cost"
          ]
        }
      ]
    },
    {
      "path": "p202 commands",
      "use": "commands [command...]",
      "short": "List every command and flag (with allowed values) in one call; --json for agents",
      "long": "Dumps the command tree: for each command its path, aliases, description, examples\nand flags (name, shorthand, type, default, usage, allowed values, required). Global\nflags are listed once under global_flags. Name a command to list only its subtree.\n\n--brief is the catalog an agent reads to choose a command: every command on one\nline (its path, summary and the web UI page it does, with that page's command line),\nand the pages no command does; about 6,000 tokens. It prints as text even where an\nagent would get JSON by default; --json gives it as JSON. Then `p202 <command> --help`\nfor the flags. To rank commands by your words instead, use `p202 search <words>`.",
      "example": "p202 commands --brief\n  p202 commands --json\n  p202 commands report\n  p202 commands --quiet",
      "runnable": true,
      "flags": [
        {
          "name": "brief",
          "type": "bool",
          "default": "false",
          "usage": "One line per command (path, summary, the UI page it does): the catalog an agent reads to choose a command",
          "required": false
        }
      ]
    },
    {
      "path": "p202 completion",
      "use": "completion",
      "short": "Generate the autocompletion script for the specified shell",
      "long": "Generate the autocompletion script for p202 for the specified shell.\nSee each sub-command's help for details on how to use the generated script.",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 completion bash",
      "use": "bash",
      "short": "Generate the autocompletion script for bash",
      "long": "Generate the autocompletion script for the bash shell.\n\nThis script depends on the 'bash-completion' package.\nIf it is not installed already, you can install it via your OS's package manager.\n\nTo load completions in your current shell session:\n\n\tsource <(p202 completion bash)\n\nTo load completions for every new session, execute once:\n\n#### Linux:\n\n\tp202 completion bash > /etc/bash_completion.d/p202\n\n#### macOS:\n\n\tp202 completion bash > $(brew --prefix)/etc/bash_completion.d/p202\n\nYou will need to start a new shell for this setup to take effect.",
      "runnable": true,
      "flags": [
        {
          "name": "no-descriptions",
          "type": "bool",
          "default": "false",
          "usage": "disable completion descriptions",
          "required": false
        }
      ]
    },
    {
      "path": "p202 completion fish",
      "use": "fish",
      "short": "Generate the autocompletion script for fish",
      "long": "Generate the autocompletion script for the fish shell.\n\nTo load completions in your current shell session:\n\n\tp202 completion fish | source\n\nTo load completions for every new session, execute once:\n\n\tp202 completion fish > ~/.config/fish/completions/p202.fish\n\nYou will need to start a new shell for this setup to take effect.",
      "runnable": true,
      "flags": [
        {
          "name": "no-descriptions",
          "type": "bool",
          "default": "false",
          "usage": "disable completion descriptions",
          "required": false
        }
      ]
    },
    {
      "path": "p202 completion powershell",
      "use": "powershell",
      "short": "Generate the autocompletion script for powershell",
      "long": "Generate the autocompletion script for powershell.\n\nTo load completions in your current shell session:\n\n\tp202 completion powershell | Out-String | Invoke-Expression\n\nTo load completions for every new session, add the output of the above command\nto your powershell profile.",
      "runnable": true,
      "flags": [
        {
          "name": "no-descriptions",
          "type": "bool",
          "default": "false",
          "usage": "disable completion descriptions",
          "required": false
        }
      ]
    },
    {
      "path": "p202 completion zsh",
      "use": "zsh",
      "short": "Generate the autocompletion script for zsh",
      "long": "Generate the autocompletion script for the zsh shell.\n\nIf shell completion is not already enabled in your environment you will need\nto enable it.  You can execute the following once:\n\n\techo \"autoload -U compinit; compinit\" >> ~/.zshrc\n\nTo load completions in your current shell session:\n\n\tsource <(p202 completion zsh)\n\nTo load completions for every new session, execute once:\n\n#### Linux:\n\n\tp202 completion zsh > \"${fpath[1]}/_p202\"\n\n#### macOS:\n\n\tp202 completion zsh > $(brew --prefix)/share/zsh/site-functions/_p202\n\nYou will need to start a new shell for this setup to take effect.",
      "runnable": true,
      "flags": [
        {
          "name": "no-descriptions",
          "type": "bool",
          "default": "false",
          "usage": "disable completion descriptions",
          "required": false
        }
      ]
    },
    {
      "path": "p202 config",
      "use": "config",
      "short": "Manage CLI configuration",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 config add-profile",
      "use": "add-profile <name>",
      "short": "Create a named profile",
      "runnable": true,
      "flags": [
        {
          "name": "key",
          "type": "string",
          "default": "",
          "usage": "Profile API key (required)",
          "required": true
        },
        {
          "name": "url",
          "type": "string",
          "default": "",
          "usage": "Profile base URL (required)",
          "required": true
        }
      ]
    },
    {
      "path": "p202 config get-default",
      "use": "get-default [key]",
      "short": "Get one default value or list all defaults",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 config list-profiles",
      "use": "list-profiles",
      "short": "List all configured profiles",
      "runnable": true,
      "flags": [
        {
          "name": "tag",
          "type": "string",
          "default": "",
          "usage": "Filter profiles by tag",
          "required": false
        }
      ]
    },
    {
      "path": "p202 config remove-profile",
      "use": "remove-profile <name>",
      "short": "Remove a named profile",
      "runnable": true,
      "flags": [
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        }
      ]
    },
    {
      "path": "p202 config rename-profile",
      "use": "rename-profile <old> <new>",
      "short": "Rename a profile",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 config set-default",
      "use": "set-default <key> <value>",
      "short": "Set a default value for supported command flags",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 config set-key",
      "use": "set-key [api-key]",
      "short": "Set the API key (omit the argument to be prompted without echoing)",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 config set-url",
      "use": "set-url <url>",
      "short": "Set the Prosper202 instance URL the API is reached at (the install's address)",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 config show",
      "use": "show",
      "short": "Show current configuration",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 config tag-profile",
      "use": "tag-profile <name> <tag> [<tag>...]",
      "short": "Add tags to a profile",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 config test",
      "use": "test",
      "short": "Test the connection to the Prosper202 instance and that the API key works",
      "long": "Checks that the instance answers (GET /system/health) and then that it accepts the\nconfigured key, and says which user the key acts as (`p202 whoami` shows more).\nThe health check alone is answered before authentication, so it passed with any key.",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 config unset-default",
      "use": "unset-default <key>",
      "short": "Remove a configured default value",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 config untag-profile",
      "use": "untag-profile <name> <tag> [<tag>...]",
      "short": "Remove tags from a profile",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 config use",
      "use": "use <name>",
      "short": "Set the active profile",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 conversion",
      "use": "conversion",
      "short": "Manage conversions (revenue events recorded via postback or pixel)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 conversion create",
      "use": "create",
      "short": "Create a conversion",
      "long": "Records a conversion on a click. --status reversed records a reversal of the click's earlier\nconversion with the same --transaction-id instead (--reversal-id is the network's id for it).\n--customer-id or --customer-ref (+ --customer-ref-type, --customer-crm) links it to an LTV\ncustomer; --item / --items-file add product line items to that customer's revenue event, so\nthey need a customer: one named here, one already linked to the click, or the account's\ncustomer c-param. The server refuses items that find none, and records nothing.\n\n  p202 conversion create --click-id 123 --payout 49 --transaction-id ORD-1 --customer-ref CUST-77 \\\n      --item '{\"sku\":\"PRO-1\",\"quantity\":1,\"unit_price\":49}'\n  p202 conversion create --click-id 123 --status reversed --transaction-id ORD-1",
      "runnable": true,
      "flags": [
        {
          "name": "click-id",
          "type": "string",
          "default": "",
          "usage": "Click ID (required)",
          "required": true
        },
        {
          "name": "click-id-public",
          "type": "string",
          "default": "",
          "usage": "Legacy alias for --click-id",
          "required": false
        },
        {
          "name": "conv-time",
          "type": "string",
          "default": "",
          "usage": "When it converted, unix seconds (default now)",
          "required": false
        },
        {
          "name": "conversion-payout",
          "type": "string",
          "default": "",
          "usage": "Legacy alias for --payout",
          "required": false
        },
        {
          "name": "customer-crm",
          "type": "string",
          "default": "",
          "usage": "CRM fields as a JSON object, applied only when this call creates the customer, e.g. '{\"email\":\"a@b.co\",\"first_name\":\"Ada\"}'",
          "required": false
        },
        {
          "name": "customer-id",
          "type": "string",
          "default": "",
          "usage": "The customer's internal id (`p202 ltv customers`)",
          "required": false
        },
        {
          "name": "customer-ref",
          "type": "string",
          "default": "",
          "usage": "Your system's id for the customer; the server finds it, or creates a customer for it",
          "required": false
        },
        {
          "name": "customer-ref-type",
          "type": "string",
          "default": "",
          "usage": "What kind of reference --customer-ref is (default custom): email_md5, email_sha256, esp_id, merchant_id, subid, custom",
          "allowed_values": [
            "email_md5",
            "email_sha256",
            "esp_id",
            "merchant_id",
            "subid",
            "custom"
          ],
          "required": false
        },
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        },
        {
          "name": "item",
          "type": "stringArray",
          "default": "[]",
          "usage": "A line item as a JSON object (repeatable), e.g. '{\"sku\":\"PRO-1\",\"name\":\"Pro plan\",\"quantity\":1,\"unit_price\":49}'",
          "required": false
        },
        {
          "name": "items-file",
          "type": "string",
          "default": "",
          "usage": "Line items as a JSON array in a file (- for stdin), instead of --item",
          "required": false
        },
        {
          "name": "payout",
          "type": "string",
          "default": "",
          "usage": "Payout amount",
          "required": false
        },
        {
          "name": "reversal-id",
          "type": "string",
          "default": "",
          "usage": "The network's id for the reversal (with --status reversed)",
          "required": false
        },
        {
          "name": "status",
          "type": "string",
          "default": "",
          "usage": "Record a reversal of the click's conversion with this --transaction-id: reversed",
          "allowed_values": [
            "reversed"
          ],
          "required": false
        },
        {
          "name": "transaction-id",
          "type": "string",
          "default": "",
          "usage": "Transaction ID for deduplication",
          "required": false
        }
      ]
    },
    {
      "path": "p202 conversion delete",
      "use": "delete <id>",
      "short": "Delete a conversion",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated conversion IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 conversion delete-subids",
      "use": "delete-subids <file|->",
      "short": "Delete the conversions of a list of subids, one per line (the UI's Delete Subids)",
      "long": "The reverse of mark-subids: every live conversion of each subid's click is cleared through\nthe ledger (soft-deleted, its revenue voided, the click's value recomputed), so the click\nis no longer a lead; the click itself stays. A subid of another account is left alone.\n\nIt reads the list first (--dry-run stops there), says how many conversions it would clear,\nand asks (--force skips). Lines are answered cleared (would_clear), not_found, not_a_subid\nor duplicate_in_list, with the file's line numbers. Running it twice is safe.\n\nNeeds a role with access_to_update_section AND delete_individual_subids, and a key with\nconversions:write. Cannot be staged. To clear a whole campaign, use reset-subids.",
      "example": "p202 conversion delete-subids wrong-subids.txt --dry-run\n  p202 conversion delete-subids wrong-subids.txt --force --json",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Say what each line would clear and write nothing",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Delete without asking",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 conversion delete-subids",
          "ui_pages": [
            "Update › Delete Subids"
          ]
        }
      ]
    },
    {
      "path": "p202 conversion get",
      "use": "get <id>",
      "short": "Get a conversion by ID",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 conversion import",
      "use": "import <file>",
      "short": "Record a network's conversion export (CSV or JSON) against its clicks, safely re-runnable",
      "long": "Reads a network's conversion export — a CSV file with a header row, or a JSON array of\nobjects — and records each line as a conversion on the click its subid names.\n\nColumns (auto-detected from the header, case and punctuation ignored; the flags override):\n  subid           required: subid, sub_id, aff_sub, sub1, click_id, clickid, s2 (--subid-column)\n  payout          optional: payout, commission, amount, revenue (--payout-column); $ and\n                  thousands separators (1,234.50) are dropped, a decimal comma (12,50) is\n                  refused; absent = the campaign's default payout\n  transaction id  optional: transaction_id, order_id, txid (--txid-column)\n  time            optional: date, time, conversion_date, created_at (--time-column); unix\n                  seconds or ms, or 2026-02-03[ 14:05[:00]] in --timezone (default UTC),\n                  RFC 3339, or any Go layout given with --time-format; absent = now\nMore than one candidate header for a column is refused: name the one to use.\n\nThe subid is read as the postback (gpb.php) reads it: the click id, digits only, no\nleading zero. Rows are marked invalid (with the reason) or duplicate_in_file (the same\nclick and transaction id as an earlier row; without a transaction id a click converts\nonce, as the postback does). A negative payout with a transaction id reverses that sale;\nnegative rows are sent after the sales, so a newest-first report reverses the right one.\n\n--dry-run shows that plan without contacting the server; add --check-clicks to also read\neach click's conversions (GET /clicks/{id}/conversions, read-only, once per click).\nWithout --dry-run the clicks are always read first, then you confirm (--force skips;\n--staged records proposals instead), then each ready row is sent as POST /conversions\nwith an Idempotency-Key derived from its click, transaction id, payout and time.\n\nStatuses: created, duplicate (the click already has it: same transaction id, or any\nconversion for an id-less row, or the key was replayed, or the server answered it as a\nduplicate or as a deleted conversion's transaction id), conflict (the click has the\ntransaction id with another payout or time; not sent), click_not_found, failed (with\nthe server's message), staged, invalid, duplicate_in_file (ready in a dry run). Re-running\nthe same file is safe: recorded rows come back as duplicate. Exit 5 if any row failed or\nconflicts; re-running the same command then sends only the rows not yet recorded.",
      "example": "p202 conversion import a2hosting-feb.csv --dry-run\n  p202 conversion import a2hosting-feb.csv --dry-run --check-clicks\n  p202 conversion import export.csv --subid-column 'Sub ID 2' --time-column 'Sale Date' --timezone America/New_York\n  p202 conversion import conversions.json --force --json",
      "runnable": true,
      "flags": [
        {
          "name": "check-clicks",
          "type": "bool",
          "default": "false",
          "usage": "With --dry-run, also read each click's conversions to show click_not_found and duplicate rows",
          "required": false
        },
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Show the plan and write nothing (no request unless --check-clicks)",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip the confirmation prompt",
          "required": false
        },
        {
          "name": "payout-column",
          "type": "string",
          "default": "",
          "usage": "Header of the payout column (default: auto-detect; with no payout column the campaign's default payout applies)",
          "required": false
        },
        {
          "name": "subid-column",
          "type": "string",
          "default": "",
          "usage": "Header of the column holding the Prosper202 subid (default: auto-detect)",
          "required": false
        },
        {
          "name": "time-column",
          "type": "string",
          "default": "",
          "usage": "Header of the conversion time column (default: auto-detect; with no time column the server records now)",
          "required": false
        },
        {
          "name": "time-format",
          "type": "string",
          "default": "",
          "usage": "Go time layout of the time column, e.g. '01/02/2006 15:04' (default: unix or ISO dates)",
          "required": false
        },
        {
          "name": "timezone",
          "type": "string",
          "default": "UTC",
          "usage": "Zone of times written without one: UTC, an IANA name, or an offset like -05:00",
          "required": false
        },
        {
          "name": "txid-column",
          "type": "string",
          "default": "",
          "usage": "Header of the transaction id column (default: auto-detect)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 conversion list",
      "use": "list",
      "short": "List conversions",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by campaign ID",
          "required": false
        },
        {
          "name": "all",
          "type": "bool",
          "default": "false",
          "usage": "Fetch all rows across pages",
          "required": false
        },
        {
          "name": "click-id",
          "type": "string",
          "default": "",
          "usage": "Only this click's conversions (see also `p202 click conversions <id>`)",
          "required": false
        },
        {
          "name": "goal",
          "type": "string",
          "default": "",
          "usage": "Only this goal's outcomes, every version (goal id from `p202 goal list`)",
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "source",
          "type": "string",
          "default": "",
          "usage": "Only conversions from this source: pixel, postback, universal_pixel, api, subid_upload, revenue_upload, legacy_pixel, clickbank, app_install, goal, legacy_baseline",
          "allowed_values": [
            "pixel",
            "postback",
            "universal_pixel",
            "api",
            "subid_upload",
            "revenue_upload",
            "legacy_pixel",
            "clickbank",
            "app_install",
            "goal",
            "legacy_baseline"
          ],
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "End, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
          "required": false
        }
      ]
    },
    {
      "path": "p202 conversion mark-subids",
      "use": "mark-subids <file|->",
      "short": "Mark clicks converted from a list of subids, one per line (the UI's Update Subids)",
      "long": "Records each subid's click as converted, at its campaign's payout, through the conversion\nledger (source subid_upload) — once per click: a click that is already a lead is answered\nalready_converted and nothing is added, so running the same list twice is safe.\n\nThe file holds one subid (a click id) per line; - reads the list from piped stdin. Every\nline is answered with its file line number: marked (would_mark with --dry-run),\nalready_converted, not_found (no click of this account), not_a_subid, or duplicate_in_list.\nA long list is sent 1,000 lines a request; when one fails, the lines before it stand and\nrunning the command again marks the rest.\n\nNeeds a role with access_to_update_section and a key with conversions:write. Cannot be staged.",
      "example": "p202 conversion mark-subids subids.txt --dry-run\n  p202 conversion mark-subids subids.txt\n  cut -d, -f2 network-report.csv | p202 conversion mark-subids - --json",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Say what each line would do and write nothing",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 conversion mark-subids",
          "ui_pages": [
            "Update › Update Subids"
          ]
        }
      ]
    },
    {
      "path": "p202 conversion pixel",
      "use": "pixel",
      "short": "Print the conversion pixel for your thank-you page (Setup > Postback / Pixel)",
      "long": "Prints the pixel Setup > Postback / Pixel shows, to put on the conversion or\nthank-you page:\n\n  --type simple     an image pixel (gpx.php): one click tracked at a time (default)\n  --type advanced   the same with cid (--campaign): several clicks at once\n  --type universal  the universal smart pixel (upx.php), which also fires your\n                    traffic sources' pixels: a JavaScript tag with a fallback for\n                    browsers without JavaScript, or a plain iframe with --iframe\n\nStdout is the pixel alone, under --quiet too: the image or iframe tag on one line,\nor the universal JavaScript tag as the page writes it (a <script> block and its\n<noscript> fallback, over several lines); --json prints every pixel and postback\nthe page shows.\nNeeds a role with access_to_setup_section.",
      "example": "p202 conversion pixel\n  p202 conversion pixel --type advanced --campaign 3 --amount 12.50\n  p202 conversion pixel --type universal --iframe",
      "runnable": true,
      "flags": [
        {
          "name": "amount",
          "type": "string",
          "default": "",
          "usage": "Amount: a number, or your network's payout macro such as {payout}; empty pays the campaign's payout",
          "required": false
        },
        {
          "name": "campaign",
          "type": "string",
          "default": "",
          "usage": "Campaign ID the advanced pixel reports under (fills cid; from p202 campaign list)",
          "required": false
        },
        {
          "name": "iframe",
          "type": "bool",
          "default": "false",
          "usage": "Print the universal pixel's plain iframe instead of its JavaScript tag",
          "required": false
        },
        {
          "name": "scheme",
          "type": "string",
          "default": "",
          "usage": "http or https (default: the scheme the tracking domain is reached on): http, https",
          "allowed_values": [
            "http",
            "https"
          ],
          "required": false
        },
        {
          "name": "subid",
          "type": "string",
          "default": "",
          "usage": "Your network's sub id macro, such as {aff_sub}, #s1#, xxC1xx or [=SID=]; empty leaves subid= for you to fill",
          "required": false
        },
        {
          "name": "type",
          "type": "string",
          "default": "",
          "usage": "Pixel type: simple, advanced, universal (default simple; advanced when --campaign is given): simple, advanced, universal",
          "allowed_values": [
            "simple",
            "advanced",
            "universal"
          ],
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 conversion pixel",
          "phrases": [
            "conversion pixel",
            "thank you page pixel",
            "tracking pixel"
          ]
        }
      ]
    },
    {
      "path": "p202 conversion postback-url",
      "use": "postback-url",
      "short": "Print the server-to-server postback URL to give your affiliate network (Setup > Postback / Pixel)",
      "long": "Prints the postback URL Setup > Postback / Pixel shows: gpb.php on this install's\ntracking domain, which the network calls with the conversion's sub id (and amount).\n\n  --subid   the network's sub id macro, e.g. {aff_sub} (HasOffers), #s2# (Cake)\n  --amount  a number or the network's payout macro, e.g. {payout}; empty pays the\n            campaign's payout\n  --campaign <id>  the advanced postback, which also carries cid\n\nStdout is the URL alone, under --quiet too; --json prints every pixel and postback\nthe page shows.\nIf the network only supports sid, change ?subid= to ?sid=. Needs a role with\naccess_to_setup_section.",
      "example": "p202 conversion postback-url --subid '{aff_sub}' --amount '{payout}'\n  p202 conversion postback-url --campaign 3 --subid '#s2#'",
      "runnable": true,
      "flags": [
        {
          "name": "amount",
          "type": "string",
          "default": "",
          "usage": "Amount: a number, or your network's payout macro such as {payout}; empty pays the campaign's payout",
          "required": false
        },
        {
          "name": "campaign",
          "type": "string",
          "default": "",
          "usage": "Campaign ID the advanced pixel reports under (fills cid; from p202 campaign list)",
          "required": false
        },
        {
          "name": "scheme",
          "type": "string",
          "default": "",
          "usage": "http or https (default: the scheme the tracking domain is reached on): http, https",
          "allowed_values": [
            "http",
            "https"
          ],
          "required": false
        },
        {
          "name": "subid",
          "type": "string",
          "default": "",
          "usage": "Your network's sub id macro, such as {aff_sub}, #s1#, xxC1xx or [=SID=]; empty leaves subid= for you to fill",
          "required": false
        },
        {
          "name": "type",
          "type": "string",
          "default": "",
          "usage": "Pixel type: simple, advanced (default simple; advanced when --campaign is given): simple, advanced",
          "allowed_values": [
            "simple",
            "advanced"
          ],
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 conversion postback-url",
          "ui_pages": [
            "Setup › Postback/Pixel"
          ],
          "phrases": [
            "postback url",
            "s2s postback",
            "server to server postback"
          ]
        }
      ]
    },
    {
      "path": "p202 conversion reset-subids",
      "use": "reset-subids",
      "short": "Clear every conversion of a category or one of its campaigns (the UI's Reset Campaign Subids)",
      "long": "Clears every conversion of the category (--aff-network-id), or of one campaign in it\n(--aff-campaign-id), so a report uploaded by mistake can be uploaded again: each converted\nclick is cleared through the ledger and the data engine rebuilds the hours. Clicks stay.\n\nIt counts the clicks first (--dry-run stops there) and asks (--force skips). Running it\nagain is safe: it clears what is left.\n\nNeeds a role with access_to_update_section and a key with conversions:write. Cannot be staged.",
      "example": "p202 conversion reset-subids --aff-network-id 3 --dry-run\n  p202 conversion reset-subids --aff-network-id 3 --aff-campaign-id 12 --force",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Only this campaign of the category (id from `p202 campaign list`; default: every campaign in it)",
          "required": false
        },
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "The category whose subids to reset (id from `p202 aff-network list`; required)",
          "required": false
        },
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Count the clicks and write nothing",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Reset without asking",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 conversion reset-subids",
          "ui_pages": [
            "Update › Reset Campaign Subids"
          ]
        }
      ]
    },
    {
      "path": "p202 conversion simulate",
      "use": "simulate",
      "short": "Prove the click -> subid -> postback -> conversion loop works for a tracker",
      "long": "Fires a synthetic click through the tracker, reads back the subid, fires the\nreal S2S postback (gpb.php), and reports whether it was accepted — so you can\nvalidate the loop before pointing a network's postback at this instance.",
      "runnable": true,
      "flags": [
        {
          "name": "payout",
          "type": "string",
          "default": "1.00",
          "usage": "Conversion payout amount to post",
          "required": false
        },
        {
          "name": "tracker",
          "type": "string",
          "default": "",
          "usage": "Internal tracker_id to simulate a conversion through",
          "required": false
        }
      ]
    },
    {
      "path": "p202 conversion upload-revenue",
      "use": "upload-revenue <file.csv>",
      "short": "Record a network's revenue report, a CSV of subid and commission (the UI's Upload Revenue Reports)",
      "long": "Records each line of the report as a conversion of a new upload batch on its subid's\nclick (source revenue_upload), at the line's commission. A click's lines in one report are\nsummed, and the newest report replaces what earlier reports and conversions set for that\nclick — so uploading a corrected report fixes the old one.\n\nColumns are read from the header when it names them plainly (subid: sub id, click id,\nt202…, aff_sub, sid; commission: commission, payout, revenue, amount, earning, sale,\nincome); name others with --subid-column/--amount-column (a header, or a 0-based column\nnumber). The report is read on the server first (--dry-run stops there), then you confirm\n(--force skips). Lines not recorded are listed with the reason, the first 1,000 of them, and\nevery skipped line is counted by reason. Unlike `conversion import`,\nthis is the UI's upload: one batch, values replacing earlier uploads, no transaction ids.\n\nNeeds a role with access_to_update_section and a key with conversions:write. At most 8 MB.\nCannot be staged.",
      "example": "p202 conversion upload-revenue march.csv --dry-run\n  p202 conversion upload-revenue march.csv --subid-column 'Sub ID 2' --amount-column Commission\n  p202 conversion upload-revenue report.csv --subid-column 0 --amount-column 3 --force --json",
      "runnable": true,
      "flags": [
        {
          "name": "amount-column",
          "type": "string",
          "default": "",
          "usage": "The commission column: its header, or a 0-based column number (default: read from the header)",
          "required": false
        },
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Read the report on the server and write nothing",
          "required": false
        },
        {
          "name": "file-name",
          "type": "string",
          "default": "",
          "usage": "The name the upload is listed under (default: the file's name)",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Upload without asking",
          "required": false
        },
        {
          "name": "subid-column",
          "type": "string",
          "default": "",
          "usage": "The subid column: its header, or a 0-based column number (default: read from the header)",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 conversion upload-revenue",
          "ui_pages": [
            "Update › Upload Revenue Reports"
          ],
          "phrases": [
            "commission report",
            "network revenue csv"
          ]
        }
      ]
    },
    {
      "path": "p202 dashboard",
      "use": "dashboard",
      "short": "Get dashboard overview — total clicks, conversions, revenue, cost, profit, and ROI for a period",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by INTERNAL campaign id (from `campaign list`), not the public id in tracking URLs",
          "required": false
        },
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by affiliate network ID",
          "required": false
        },
        {
          "name": "all-profiles",
          "type": "bool",
          "default": "false",
          "usage": "Run against all configured profiles",
          "required": false
        },
        {
          "name": "browser-id",
          "type": "string",
          "default": "",
          "usage": "Filter by browser ID (the id of a `--breakdown browser` row)",
          "required": false
        },
        {
          "name": "country-id",
          "type": "string",
          "default": "",
          "usage": "Filter by country ID",
          "required": false
        },
        {
          "name": "device-type",
          "type": "string",
          "default": "",
          "usage": "Filter by device type ID: 1 Desktop, 2 Mobile, 3 Tablet, 4 Bot (the ids of `--breakdown device_type` rows)",
          "required": false
        },
        {
          "name": "ip",
          "type": "string",
          "default": "",
          "usage": "Only clicks from this one IP address, IPv4 or IPv6",
          "required": false
        },
        {
          "name": "isp-id",
          "type": "string",
          "default": "",
          "usage": "Filter by ISP/carrier ID (the id of a `--breakdown isp` row)",
          "required": false
        },
        {
          "name": "keyword",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose keyword contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Filter by landing page ID",
          "required": false
        },
        {
          "name": "method-of-promotion",
          "type": "string",
          "default": "",
          "usage": "Only direct-link clicks or only landing-page clicks: directlink, landingpage",
          "allowed_values": [
            "directlink",
            "landingpage"
          ],
          "required": false
        },
        {
          "name": "period",
          "shorthand": "p",
          "type": "string",
          "default": "",
          "usage": "Period (default today): today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "platform-id",
          "type": "string",
          "default": "",
          "usage": "Filter by platform (OS) ID (the id of a `--breakdown platform` row)",
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC account ID",
          "required": false
        },
        {
          "name": "ppc-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC network ID, or none for the clicks with no traffic source",
          "required": false
        },
        {
          "name": "profiles",
          "type": "string",
          "default": "",
          "usage": "Comma-separated profile names",
          "required": false
        },
        {
          "name": "referer",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose referring URL contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "region-id",
          "type": "string",
          "default": "",
          "usage": "Filter by region ID (the id of a `--breakdown region` row)",
          "required": false
        },
        {
          "name": "show",
          "type": "string",
          "default": "",
          "usage": "Which clicks count (default all): all, real, filtered, filtered_bot, leads; real = not filtered, filtered_bot = filtered as bots, leads = converted",
          "allowed_values": [
            "all",
            "real",
            "filtered",
            "filtered_bot",
            "leads"
          ],
          "required": false
        },
        {
          "name": "text-ad-id",
          "type": "string",
          "default": "",
          "usage": "Filter by text ad ID",
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "End, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 dashboard",
          "phrases": [
            "overall performance",
            "how are we doing",
            "performance today",
            "profit and roi"
          ]
        }
      ]
    },
    {
      "path": "p202 diff",
      "use": "diff <entity|all>",
      "short": "Compare entities between two profiles",
      "runnable": true,
      "flags": [
        {
          "name": "from",
          "type": "string",
          "default": "",
          "usage": "Source profile name (alias: --source)",
          "required": false
        },
        {
          "name": "source",
          "type": "string",
          "default": "",
          "usage": "Source profile (alias of --from)",
          "required": false
        },
        {
          "name": "target",
          "type": "string",
          "default": "",
          "usage": "Target profile (alias of --to)",
          "required": false
        },
        {
          "name": "to",
          "type": "string",
          "default": "",
          "usage": "Target profile name (alias: --target)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 eval",
      "use": "eval",
      "short": "Behavioral evals for an agent that operates this instance",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 eval run",
      "use": "run",
      "short": "Run eval cases against a pluggable agent command",
      "long": "Run behavioral snapshot evals: for each case the runner performs the setup\ncommands, hands the ask to --agent-cmd (stdin and $P202_EVAL_ASK), captures\nevery `p202` invocation the agent makes (a PATH shim — no adapter needed),\nre-reads instance state, and grades the case's expectations. Cases follow\nthe shape in .claude/skills/p202-agent-evals/SKILL.md; a starter file ships\nin tests/fixtures/agent-eval/cases/.\n\nThe agent command must read the ask, drive `p202` (the one on PATH — that\nis the capture shim), print the agent's reply to stdout, and exit 0.\nThe shim records each command's exit status: runs_one_of credits only a\ncommand that exited 0 (or the case's runs_one_of_exit), and names the\nstatus of a matching command that failed; never_runs counts every\nattempt. Each result's commands_failed counts what did not exit 0.\nRubric grading is optional: --judge-cmd receives {id, ask, rubric, reply,\ncommands, runs} as JSON on stdin (runs: each command with its exit_code)\nand must print a line starting with PASS or FAIL; without it, rubric\ncases report needs_judge instead of pass.\n\nExit codes: 0 when nothing failed; 5 (partial_failure) when cases failed\nor errored — results are still on stdout.",
      "runnable": true,
      "flags": [
        {
          "name": "agent-cmd",
          "type": "string",
          "default": "",
          "usage": "Shell command that runs the agent under test (required)",
          "required": true
        },
        {
          "name": "cases",
          "type": "string",
          "default": "",
          "usage": "Case file or directory of *.json case files (required)",
          "required": true
        },
        {
          "name": "judge-cmd",
          "type": "string",
          "default": "",
          "usage": "Shell command that grades rubrics (stdin: JSON; stdout: PASS/FAIL verdict)",
          "required": false
        },
        {
          "name": "only",
          "type": "string",
          "default": "",
          "usage": "Comma-separated case ids to run",
          "required": false
        },
        {
          "name": "p202-bin",
          "type": "string",
          "default": "",
          "usage": "Real p202 binary the capture shim execs (default: this binary)",
          "required": false
        },
        {
          "name": "priority",
          "type": "string",
          "default": "",
          "usage": "Priorities to run: critical, high, medium, low; comma-separated for several",
          "allowed_values": [
            "critical",
            "high",
            "medium",
            "low"
          ],
          "value_list": true,
          "required": false
        },
        {
          "name": "timeout",
          "type": "int",
          "default": "300",
          "usage": "Per-command timeout in seconds (agent, setup, checks)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 event",
      "use": "event",
      "short": "Report web events on a click (evaluated by its campaign's goals)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 event send",
      "use": "send",
      "short": "Send an event (or a file of events) for a click",
      "long": "Stores the event on the click and evaluates the click's campaign goals, in one\ntransaction: a goal it reaches records a conversion (and tells the traffic source when\nthe campaign pays for it and notifies). --id is your id for the event: sending the same\nid again is answered as a duplicate and records nothing, so a retry is always safe.\n\n  p202 event send --click-id 123 --name purchase --id ORD-1 --revenue 49 --props '{\"plan\":\"pro\"}'\n  p202 event send --click-id 123 --file events.json   # a JSON list of events, or {\"events\": […]}",
      "runnable": true,
      "flags": [
        {
          "name": "click-id",
          "type": "string",
          "default": "",
          "usage": "The click the events belong to (`p202 click list`)",
          "required": false
        },
        {
          "name": "file",
          "shorthand": "F",
          "type": "string",
          "default": "",
          "usage": "Send the events in a JSON file (- for stdin) instead of one from the flags",
          "required": false
        },
        {
          "name": "id",
          "type": "string",
          "default": "",
          "usage": "Your id for the event: resending it is recorded once",
          "required": false
        },
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        },
        {
          "name": "name",
          "type": "string",
          "default": "",
          "usage": "The event name, e.g. purchase",
          "required": false
        },
        {
          "name": "occurred-at",
          "type": "string",
          "default": "",
          "usage": "When it happened, unix seconds (default: now, by the server's clock)",
          "required": false
        },
        {
          "name": "props",
          "type": "string",
          "default": "",
          "usage": "Properties as a JSON object, e.g. '{\"plan\":\"pro\"}'",
          "required": false
        },
        {
          "name": "revenue",
          "type": "string",
          "default": "",
          "usage": "What it was worth (paid by a goal valued from the event's amount)",
          "required": false
        },
        {
          "name": "transaction-id",
          "type": "string",
          "default": "",
          "usage": "The network's id for it, kept on the conversion",
          "required": false
        }
      ]
    },
    {
      "path": "p202 exec",
      "use": "exec [flags] -- <subcommand...>",
      "short": "Run a subcommand across multiple profiles",
      "runnable": true,
      "flags": [
        {
          "name": "all-profiles",
          "type": "bool",
          "default": "false",
          "usage": "Run against all configured profiles",
          "required": false
        },
        {
          "name": "concurrency",
          "type": "int",
          "default": "5",
          "usage": "Number of concurrent profile executions",
          "required": false
        },
        {
          "name": "profiles",
          "type": "string",
          "default": "",
          "usage": "Comma-separated profile names",
          "required": false
        }
      ]
    },
    {
      "path": "p202 export",
      "use": "export <entity|all>",
      "short": "Export entities to JSON",
      "runnable": true,
      "flags": [
        {
          "name": "output",
          "shorthand": "O",
          "type": "string",
          "default": "",
          "usage": "Output file path (-O; -o is reserved for --offset)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 forecast",
      "use": "forecast",
      "aliases": [
        "predict"
      ],
      "short": "Forecast future performance metrics using historical data",
      "long": "Forecast future values for any tracked metric using statistical methods.\n\nFetches historical time-series data from your Prosper202 instance and projects\nit forward using the selected algorithm. Supports linear regression, simple\nand weighted moving averages, damped-trend Holt-Winters exponential smoothing,\nand an ensemble (the default, alias \"auto\") that combines the methods weighted\nby rolling-backtest accuracy and reports each member's share.\n\nWith --seasonal, predictions are modulated by a day-of-week profile learned\nfrom the fetched history itself (re-estimated inside every backtest fold, so\nthe bands describe the profiled forecast) to account for weekly patterns\n(e.g., \"Tuesdays always convert better\"). Requires --interval day or hour.\n\nEvent-aware forecasting (--events, --event-tag) uses stored calendar events and\nrequires --interval day.\n\nDerived metrics (leads, income, cost, net) requested without --seasonal or\n--events are composed from driver forecasts (clicks and the linking rates),\nso leads = clicks x conv_rate, income = leads x avg_payout, and net =\nincome - cost hold exactly; --all-metrics forecasts all core metrics\ntogether this way.\n\nBounds are empirical quantiles from a rolling backtest (meta \"bounds\" names\nthe pair, e.g. p05-p95 (90%)); short histories fall back to Gaussian bounds\n(meta \"bounds_source\"). Short outlier runs such as a tracking outage are\nmasked from fitting and listed in meta \"anomalies_masked\"; a detected level\nshift is reported as \"level_shift_at\" and the new regime is fitted. Use\n--no-anomaly-mask / --no-level-shift to fit the history exactly as-is.\n\nExamples:\n  p202 forecast --metric revenue --horizon 7\n  p202 forecast --metric clicks --history last90 --method linear\n  p202 forecast --metric profit --horizon 14 --method auto --seasonal\n  p202 forecast --all-metrics --horizon 7\n  p202 forecast --metric conv_rate --history last30 --interval week --horizon 4\n  p202 forecast --metric revenue --aff-campaign-id 5 --horizon 7\n  p202 forecast --metric revenue --events --horizon 14\n  p202 forecast --metric clicks --events --event-tag us-holidays\n  p202 forecast --metric clicks --no-anomaly-mask --json",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by campaign ID",
          "required": false
        },
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by affiliate network ID",
          "required": false
        },
        {
          "name": "all-metrics",
          "type": "bool",
          "default": "false",
          "usage": "Forecast clicks, leads, income, cost, and net together via ratio decomposition (coherent output)",
          "required": false
        },
        {
          "name": "anomaly-cycles",
          "type": "int",
          "default": "4",
          "usage": "Seasonal cycles on each side used as same-weekday/hour references for transient masking",
          "required": false
        },
        {
          "name": "anomaly-sigma",
          "type": "float64",
          "default": "5",
          "usage": "Transient-masking threshold in robust sigma units (lower masks more aggressively)",
          "required": false
        },
        {
          "name": "confidence",
          "type": "float64",
          "default": "0.95",
          "usage": "Confidence level for prediction bounds; snaps to the nearest band: 0.50 (p25-p75), 0.80 (p10-p90), or 0.90 (p05-p95, also used for 0.95/0.99)",
          "required": false
        },
        {
          "name": "country-id",
          "type": "string",
          "default": "",
          "usage": "Filter by country ID",
          "required": false
        },
        {
          "name": "days",
          "type": "string",
          "default": "",
          "usage": "Alias of --history: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "event-tag",
          "type": "string",
          "default": "",
          "usage": "Filter forecast events by tag (comma-separated, e.g. us-holidays,promos)",
          "required": false
        },
        {
          "name": "events",
          "type": "bool",
          "default": "false",
          "usage": "Enable event-aware forecasting using stored forecast events",
          "required": false
        },
        {
          "name": "history",
          "type": "string",
          "default": "last90",
          "usage": "Historical data period (aliases: --period, --days): today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "horizon",
          "shorthand": "n",
          "type": "int",
          "default": "7",
          "usage": "Number of periods to forecast forward",
          "required": false
        },
        {
          "name": "interval",
          "shorthand": "i",
          "type": "string",
          "default": "day",
          "usage": "Forecast granularity: hour, day, week, month",
          "allowed_values": [
            "hour",
            "day",
            "week",
            "month"
          ],
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Filter by landing page ID",
          "required": false
        },
        {
          "name": "method",
          "type": "string",
          "default": "auto",
          "usage": "Forecasting method (auto = ensemble): linear, sma, wma, holtwinters, ensemble, auto",
          "allowed_values": [
            "linear",
            "sma",
            "wma",
            "holtwinters",
            "ensemble",
            "auto"
          ],
          "required": false
        },
        {
          "name": "metric",
          "shorthand": "m",
          "type": "string",
          "default": "",
          "usage": "Metric to forecast: total_clicks, total_click_throughs, total_leads, total_income, total_cost, total_net, epc, avg_cpc, conv_rate, roi, cpa (aliases: clicks=total_clicks, conversions=total_leads, cost=total_cost, income=total_income, leads=total_leads, net=total_net, profit=total_net, revenue=total_income)",
          "allowed_values": [
            "total_clicks",
            "total_click_throughs",
            "total_leads",
            "total_income",
            "total_cost",
            "total_net",
            "epc",
            "avg_cpc",
            "conv_rate",
            "roi",
            "cpa"
          ],
          "value_aliases": {
            "clicks": "total_clicks",
            "conversions": "total_leads",
            "cost": "total_cost",
            "income": "total_income",
            "leads": "total_leads",
            "net": "total_net",
            "profit": "total_net",
            "revenue": "total_income"
          },
          "required": false
        },
        {
          "name": "no-anomaly-mask",
          "type": "bool",
          "default": "false",
          "usage": "Disable transient masking (fit short outlier runs such as tracking outages as data)",
          "required": false
        },
        {
          "name": "no-level-shift",
          "type": "bool",
          "default": "false",
          "usage": "Disable level-shift detection (fit the full history as-is)",
          "required": false
        },
        {
          "name": "period",
          "type": "string",
          "default": "",
          "usage": "Alias of --history: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC account ID",
          "required": false
        },
        {
          "name": "ppc-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC network ID",
          "required": false
        },
        {
          "name": "seasonal",
          "type": "bool",
          "default": "false",
          "usage": "Apply a day-of-week profile learned from the fetched history (hour interval also gets an hour-of-day profile)",
          "required": false
        },
        {
          "name": "seasonal-monthly",
          "type": "bool",
          "default": "false",
          "usage": "Apply day-of-month seasonal adjustment learned from the fetched series (requires --interval day)",
          "required": false
        },
        {
          "name": "window",
          "type": "int",
          "default": "0",
          "usage": "SMA/WMA window size (0 = auto-select)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 forecast-event",
      "use": "forecast-event",
      "short": "Manage forecast events (holidays, promotions, anomalies that affect forecasting)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 forecast-event create",
      "use": "create",
      "short": "Create a new forecast-event",
      "example": "p202 forecast-event create --event-name <event_name> --event-date <event_date> --json",
      "runnable": true,
      "flags": [
        {
          "name": "end-date",
          "type": "string",
          "default": "",
          "usage": "End date for multi-day events (YYYY-MM-DD)",
          "required": false
        },
        {
          "name": "event-date",
          "type": "string",
          "default": "",
          "usage": "Event date (YYYY-MM-DD) (required)",
          "required": true
        },
        {
          "name": "event-name",
          "type": "string",
          "default": "",
          "usage": "Event name (e.g. 'Black Friday', 'Server Outage') (required)",
          "required": true
        },
        {
          "name": "expected-impact-pct",
          "type": "string",
          "default": "",
          "usage": "Expected impact percentage (e.g. +200 for 3x boost, -50 for half)",
          "required": false
        },
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        },
        {
          "name": "impact-type",
          "type": "string",
          "default": "",
          "usage": "Impact type: boost, suppress, neutral",
          "allowed_values": [
            "boost",
            "suppress",
            "neutral"
          ],
          "required": false
        },
        {
          "name": "lag-days",
          "type": "string",
          "default": "",
          "usage": "Days after event that impact decays",
          "required": false
        },
        {
          "name": "lead-days",
          "type": "string",
          "default": "",
          "usage": "Days before event that impact ramps up",
          "required": false
        },
        {
          "name": "notes",
          "type": "string",
          "default": "",
          "usage": "Freeform notes",
          "required": false
        },
        {
          "name": "recurrence",
          "type": "string",
          "default": "",
          "usage": "Recurrence: none, monthly, yearly, custom",
          "allowed_values": [
            "none",
            "monthly",
            "yearly",
            "custom"
          ],
          "required": false
        },
        {
          "name": "tags",
          "type": "string",
          "default": "",
          "usage": "Comma-separated tags (e.g. 'us-holidays,retail')",
          "required": false
        }
      ]
    },
    {
      "path": "p202 forecast-event delete",
      "use": "delete <id>",
      "short": "Delete a forecast-event",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated forecast-event IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 forecast-event get",
      "use": "get <id>",
      "short": "Get a forecast-event by ID",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 forecast-event list",
      "use": "list",
      "short": "List forecast events (holidays, promotions, anomalies that affect forecasting)",
      "runnable": true,
      "flags": [
        {
          "name": "all",
          "type": "bool",
          "default": "false",
          "usage": "Fetch all rows across pages",
          "required": false
        },
        {
          "name": "event-name",
          "type": "string",
          "default": "",
          "usage": "Filter by event name",
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "page",
          "type": "string",
          "default": "",
          "usage": "Page number",
          "required": false
        },
        {
          "name": "recurrence",
          "type": "string",
          "default": "",
          "usage": "Filter by recurrence type: none, monthly, yearly, custom",
          "allowed_values": [
            "none",
            "monthly",
            "yearly",
            "custom"
          ],
          "required": false
        },
        {
          "name": "resolve-names",
          "type": "bool",
          "default": "false",
          "usage": "Resolve foreign key IDs to names",
          "required": false
        },
        {
          "name": "tags",
          "type": "string",
          "default": "",
          "usage": "Filter by tag",
          "required": false
        }
      ]
    },
    {
      "path": "p202 forecast-event update",
      "use": "update <id>",
      "short": "Update a forecast-event",
      "example": "p202 forecast-event update <id from p202 forecast-event list> --event-name <new value> --json\n  (only the flags given are sent; the rest of the forecast-event is unchanged)",
      "runnable": true,
      "flags": [
        {
          "name": "end-date",
          "type": "string",
          "default": "",
          "usage": "End date for multi-day events (YYYY-MM-DD) (\"\" clears it)",
          "required": false
        },
        {
          "name": "event-date",
          "type": "string",
          "default": "",
          "usage": "Event date (YYYY-MM-DD)",
          "required": false
        },
        {
          "name": "event-name",
          "type": "string",
          "default": "",
          "usage": "Event name (e.g. 'Black Friday', 'Server Outage')",
          "required": false
        },
        {
          "name": "expected-impact-pct",
          "type": "string",
          "default": "",
          "usage": "Expected impact percentage (e.g. +200 for 3x boost, -50 for half)",
          "required": false
        },
        {
          "name": "impact-type",
          "type": "string",
          "default": "",
          "usage": "Impact type: boost, suppress, neutral",
          "allowed_values": [
            "boost",
            "suppress",
            "neutral"
          ],
          "required": false
        },
        {
          "name": "lag-days",
          "type": "string",
          "default": "",
          "usage": "Days after event that impact decays",
          "required": false
        },
        {
          "name": "lead-days",
          "type": "string",
          "default": "",
          "usage": "Days before event that impact ramps up",
          "required": false
        },
        {
          "name": "notes",
          "type": "string",
          "default": "",
          "usage": "Freeform notes (\"\" clears it)",
          "required": false
        },
        {
          "name": "recurrence",
          "type": "string",
          "default": "",
          "usage": "Recurrence: none, monthly, yearly, custom",
          "allowed_values": [
            "none",
            "monthly",
            "yearly",
            "custom"
          ],
          "required": false
        },
        {
          "name": "tags",
          "type": "string",
          "default": "",
          "usage": "Comma-separated tags (e.g. 'us-holidays,retail') (\"\" clears it)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 goal",
      "use": "goal",
      "aliases": [
        "goals"
      ],
      "short": "Goals: what counts as a conversion, versioned, and which campaigns pay for it",
      "long": "Define what counts (an install, an event with conditions, the Nth occurrence, a running\nsum, a step after another goal, a window), and which campaigns pay for it and how much.\n\n  p202 goal create --campaign-id 7 --name \"Sale\" --event sale --value 20\n  p202 goal create --registration-id 3 --name \"Level 3\" --event level_reached --where \"level gte 3\"\n  p202 goal campaign set 12 7 --payout 4.00\n  p202 goal reevaluate 12            # preview; add --apply to apply\n\nThe full definition format is in documentation/api/22-goals.md; --definition takes it as JSON.",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 goal campaign",
      "use": "campaign",
      "aliases": [
        "campaigns"
      ],
      "short": "Which campaigns pay for a goal, and how much",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 goal campaign list",
      "use": "list <goal-id>",
      "short": "List the campaigns paying for a goal",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 goal campaign remove",
      "use": "remove <goal-id> <campaign-id>",
      "short": "Stop a campaign paying for a goal (its outcomes there are tracked, not paid, from now on)",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        }
      ]
    },
    {
      "path": "p202 goal campaign set",
      "use": "set <goal-id> <campaign-id>",
      "short": "Make a campaign pay for a goal, or change its payout (default: the goal's own value)",
      "runnable": true,
      "flags": [
        {
          "name": "clear-payout",
          "type": "bool",
          "default": "false",
          "usage": "Go back to the goal's own value",
          "required": false
        },
        {
          "name": "notify",
          "type": "string",
          "default": "",
          "usage": "Tell the traffic source when the goal is reached (default true): true, false (aliases: 0=false, 1=true, f=false, t=true)",
          "allowed_values": [
            "true",
            "false"
          ],
          "value_aliases": {
            "0": "false",
            "1": "true",
            "f": "false",
            "t": "true"
          },
          "required": false
        },
        {
          "name": "payout",
          "type": "string",
          "default": "",
          "usage": "Campaign payout for reaching the goal (default: the goal's own value)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 goal create",
      "use": "create",
      "short": "Create a goal for a campaign, an app registration or the account",
      "long": "Creates version 1 of a goal. Build the definition from the quick flags, or pass the\nwhole JSON with --definition/--file. A campaign goal with a value is payable on its\ncampaign straight away (--payout overrides the value there, --not-payable tracks it only).",
      "runnable": true,
      "flags": [
        {
          "name": "account",
          "type": "bool",
          "default": "false",
          "usage": "Owner: the account (shared by every app)",
          "required": false
        },
        {
          "name": "after",
          "type": "string",
          "default": "",
          "usage": "Goal ids that must be reached first, comma-separated",
          "required": false
        },
        {
          "name": "campaign-id",
          "type": "string",
          "default": "",
          "usage": "Owner: this campaign (`p202 campaign list`)",
          "required": false
        },
        {
          "name": "count",
          "type": "string",
          "default": "",
          "usage": "Reached on the Nth matching event (default 1)",
          "required": false
        },
        {
          "name": "definition",
          "type": "string",
          "default": "",
          "usage": "The whole definition as JSON (exclusive with the quick flags)",
          "required": false
        },
        {
          "name": "event",
          "type": "string",
          "default": "",
          "usage": "Trigger: the event name that reaches the goal",
          "required": false
        },
        {
          "name": "file",
          "shorthand": "F",
          "type": "string",
          "default": "",
          "usage": "Read the definition JSON from a file (- for stdin)",
          "required": false
        },
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        },
        {
          "name": "install",
          "type": "bool",
          "default": "false",
          "usage": "Trigger: the install itself",
          "required": false
        },
        {
          "name": "name",
          "type": "string",
          "default": "",
          "usage": "Goal name (unique per owner)",
          "required": false
        },
        {
          "name": "no-value",
          "type": "bool",
          "default": "false",
          "usage": "Tracked, not paid (value none)",
          "required": false
        },
        {
          "name": "no-window",
          "type": "bool",
          "default": "false",
          "usage": "Remove the window (update)",
          "required": false
        },
        {
          "name": "not-payable",
          "type": "bool",
          "default": "false",
          "usage": "Campaign goal: track it, do not pay for it",
          "required": false
        },
        {
          "name": "notify",
          "type": "string",
          "default": "",
          "usage": "Tell the traffic source when the goal is reached (default true): true, false (aliases: 0=false, 1=true, f=false, t=true)",
          "allowed_values": [
            "true",
            "false"
          ],
          "value_aliases": {
            "0": "false",
            "1": "true",
            "f": "false",
            "t": "true"
          },
          "required": false
        },
        {
          "name": "payout",
          "type": "string",
          "default": "",
          "usage": "Campaign payout for reaching the goal (default: the goal's own value)",
          "required": false
        },
        {
          "name": "registration-id",
          "type": "string",
          "default": "",
          "usage": "Owner: this app registration (`p202 app list`)",
          "required": false
        },
        {
          "name": "repeat",
          "type": "string",
          "default": "",
          "usage": "How often it can be reached (default once): once, each",
          "allowed_values": [
            "once",
            "each"
          ],
          "required": false
        },
        {
          "name": "repeat-max",
          "type": "string",
          "default": "",
          "usage": "With --repeat each: the most times it can be reached (1-10000; required for a --sum-prop goal)",
          "required": false
        },
        {
          "name": "sum-gte",
          "type": "string",
          "default": "",
          "usage": "The running-sum threshold",
          "required": false
        },
        {
          "name": "sum-prop",
          "type": "string",
          "default": "",
          "usage": "Reached when the running sum of this property (or $revenue) reaches --sum-gte",
          "required": false
        },
        {
          "name": "value",
          "type": "string",
          "default": "",
          "usage": "Fixed value of reaching the goal, e.g. 4.00",
          "required": false
        },
        {
          "name": "value-from-property",
          "type": "string",
          "default": "",
          "usage": "Value from an event property (default the event's revenue)",
          "required": false
        },
        {
          "name": "where",
          "type": "string",
          "default": "",
          "usage": "Conditions on the event, \"<prop> <op> <value>\", several separated by ; (ANDed); ops: eq, neq, gt, gte, lt, lte, in, exists",
          "required": false
        },
        {
          "name": "within-days",
          "type": "string",
          "default": "",
          "usage": "Only events within this many days of --within-from",
          "required": false
        },
        {
          "name": "within-from",
          "type": "string",
          "default": "",
          "usage": "Window anchor: install, click",
          "allowed_values": [
            "install",
            "click"
          ],
          "required": false
        }
      ]
    },
    {
      "path": "p202 goal delete",
      "use": "delete [id]",
      "short": "Archive a goal (its versions, outcomes and conversions are kept)",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated goal IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 goal evaluate",
      "use": "evaluate",
      "short": "Evaluate definitions against events without writing anything",
      "long": "Sends {\"goals\", \"subject\", \"events\"} — the format of the evaluator vectors in\ntests/fixtures/app-sdk-contract/goals/ — and prints the outcomes the server's evaluator\nreaches. Nothing is stored.",
      "runnable": true,
      "flags": [
        {
          "name": "file",
          "shorthand": "F",
          "type": "string",
          "default": "",
          "usage": "JSON body: goals, subject, events (- for stdin)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 goal get",
      "use": "get <id>",
      "short": "Get a goal: its current definition, the campaigns paying for it, its live outcome count",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 goal list",
      "use": "list",
      "short": "List goals (filter by owner)",
      "runnable": true,
      "flags": [
        {
          "name": "account",
          "type": "bool",
          "default": "false",
          "usage": "Only the account's goals",
          "required": false
        },
        {
          "name": "all",
          "type": "bool",
          "default": "false",
          "usage": "Fetch all rows across pages",
          "required": false
        },
        {
          "name": "campaign-id",
          "type": "string",
          "default": "",
          "usage": "Only this campaign's own goals",
          "required": false
        },
        {
          "name": "include-archived",
          "type": "bool",
          "default": "false",
          "usage": "Include archived goals",
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "registration-id",
          "type": "string",
          "default": "",
          "usage": "Only this app registration's goals",
          "required": false
        }
      ]
    },
    {
      "path": "p202 goal outcomes",
      "use": "outcomes <id>",
      "short": "List a goal's live outcomes (each time a click or install reached it)",
      "runnable": true,
      "flags": [
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "subject-id",
          "type": "string",
          "default": "",
          "usage": "Only this click (or install)",
          "required": false
        },
        {
          "name": "subject-type",
          "type": "string",
          "default": "",
          "usage": "Only this kind of subject: click, install",
          "allowed_values": [
            "click",
            "install"
          ],
          "required": false
        }
      ]
    },
    {
      "path": "p202 goal reevaluate",
      "use": "reevaluate <id>",
      "short": "Re-evaluate past clicks or installs under a goal version (preview; --apply to apply)",
      "long": "Without --apply, shows per subject (a click, or an Android install with --subject-type\ninstall) the outcomes that would be retired and written, and what happens to their\nconversions (superseded by the new row, or deleted when the version no longer reaches\nthe goal). Goals that wait on this one (their definition's after, directly or through\nanother) are re-decided with it: listed in goals, each row names its goal_id.\nWith --apply, does it, one subject per transaction. At most --limit subjects per call;\npass the answer's next_after as --after to continue.",
      "runnable": true,
      "flags": [
        {
          "name": "after",
          "type": "string",
          "default": "",
          "usage": "Continue after this click id (the previous answer's next_after)",
          "required": false
        },
        {
          "name": "apply",
          "type": "bool",
          "default": "false",
          "usage": "Apply the re-evaluation (without it: preview only)",
          "required": false
        },
        {
          "name": "limit",
          "type": "string",
          "default": "",
          "usage": "Clicks per call (default 100, at most 1000)",
          "required": false
        },
        {
          "name": "subject-type",
          "type": "string",
          "default": "",
          "usage": "Subjects to re-evaluate (default: click for a campaign goal, install for a registration or account goal): click, install",
          "allowed_values": [
            "click",
            "install"
          ],
          "required": false
        },
        {
          "name": "version",
          "type": "string",
          "default": "",
          "usage": "The version to re-evaluate under (default: the current one)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 goal update",
      "use": "update <id>",
      "short": "Edit a goal (a new version; conversions keep the version that produced them)",
      "long": "Replaces the goal's definition with a new version. --definition/--file give the whole\nnew definition; the quick flags change only their part of the current one. The same\ndefinition again is not a new version. Past conversions keep their version until\n`p202 goal reevaluate <id> --apply`.",
      "runnable": true,
      "flags": [
        {
          "name": "after",
          "type": "string",
          "default": "",
          "usage": "Goal ids that must be reached first, comma-separated",
          "required": false
        },
        {
          "name": "count",
          "type": "string",
          "default": "",
          "usage": "Reached on the Nth matching event (default 1)",
          "required": false
        },
        {
          "name": "definition",
          "type": "string",
          "default": "",
          "usage": "The whole definition as JSON (exclusive with the quick flags)",
          "required": false
        },
        {
          "name": "event",
          "type": "string",
          "default": "",
          "usage": "Trigger: the event name that reaches the goal",
          "required": false
        },
        {
          "name": "file",
          "shorthand": "F",
          "type": "string",
          "default": "",
          "usage": "Read the definition JSON from a file (- for stdin)",
          "required": false
        },
        {
          "name": "install",
          "type": "bool",
          "default": "false",
          "usage": "Trigger: the install itself",
          "required": false
        },
        {
          "name": "name",
          "type": "string",
          "default": "",
          "usage": "Goal name (unique per owner)",
          "required": false
        },
        {
          "name": "no-value",
          "type": "bool",
          "default": "false",
          "usage": "Tracked, not paid (value none)",
          "required": false
        },
        {
          "name": "no-window",
          "type": "bool",
          "default": "false",
          "usage": "Remove the window (update)",
          "required": false
        },
        {
          "name": "repeat",
          "type": "string",
          "default": "",
          "usage": "How often it can be reached (default once): once, each",
          "allowed_values": [
            "once",
            "each"
          ],
          "required": false
        },
        {
          "name": "repeat-max",
          "type": "string",
          "default": "",
          "usage": "With --repeat each: the most times it can be reached (1-10000; required for a --sum-prop goal)",
          "required": false
        },
        {
          "name": "sum-gte",
          "type": "string",
          "default": "",
          "usage": "The running-sum threshold",
          "required": false
        },
        {
          "name": "sum-prop",
          "type": "string",
          "default": "",
          "usage": "Reached when the running sum of this property (or $revenue) reaches --sum-gte",
          "required": false
        },
        {
          "name": "value",
          "type": "string",
          "default": "",
          "usage": "Fixed value of reaching the goal, e.g. 4.00",
          "required": false
        },
        {
          "name": "value-from-property",
          "type": "string",
          "default": "",
          "usage": "Value from an event property (default the event's revenue)",
          "required": false
        },
        {
          "name": "where",
          "type": "string",
          "default": "",
          "usage": "Conditions on the event, \"<prop> <op> <value>\", several separated by ; (ANDed); ops: eq, neq, gt, gte, lt, lte, in, exists",
          "required": false
        },
        {
          "name": "within-days",
          "type": "string",
          "default": "",
          "usage": "Only events within this many days of --within-from",
          "required": false
        },
        {
          "name": "within-from",
          "type": "string",
          "default": "",
          "usage": "Window anchor: install, click",
          "allowed_values": [
            "install",
            "click"
          ],
          "required": false
        }
      ]
    },
    {
      "path": "p202 goal validate",
      "use": "validate",
      "short": "Check a definition without saving it (answers the canonical form)",
      "runnable": true,
      "flags": [
        {
          "name": "after",
          "type": "string",
          "default": "",
          "usage": "Goal ids that must be reached first, comma-separated",
          "required": false
        },
        {
          "name": "count",
          "type": "string",
          "default": "",
          "usage": "Reached on the Nth matching event (default 1)",
          "required": false
        },
        {
          "name": "definition",
          "type": "string",
          "default": "",
          "usage": "The whole definition as JSON (exclusive with the quick flags)",
          "required": false
        },
        {
          "name": "event",
          "type": "string",
          "default": "",
          "usage": "Trigger: the event name that reaches the goal",
          "required": false
        },
        {
          "name": "file",
          "shorthand": "F",
          "type": "string",
          "default": "",
          "usage": "Read the definition JSON from a file (- for stdin)",
          "required": false
        },
        {
          "name": "install",
          "type": "bool",
          "default": "false",
          "usage": "Trigger: the install itself",
          "required": false
        },
        {
          "name": "name",
          "type": "string",
          "default": "",
          "usage": "Goal name (unique per owner)",
          "required": false
        },
        {
          "name": "no-value",
          "type": "bool",
          "default": "false",
          "usage": "Tracked, not paid (value none)",
          "required": false
        },
        {
          "name": "no-window",
          "type": "bool",
          "default": "false",
          "usage": "Remove the window (update)",
          "required": false
        },
        {
          "name": "repeat",
          "type": "string",
          "default": "",
          "usage": "How often it can be reached (default once): once, each",
          "allowed_values": [
            "once",
            "each"
          ],
          "required": false
        },
        {
          "name": "repeat-max",
          "type": "string",
          "default": "",
          "usage": "With --repeat each: the most times it can be reached (1-10000; required for a --sum-prop goal)",
          "required": false
        },
        {
          "name": "sum-gte",
          "type": "string",
          "default": "",
          "usage": "The running-sum threshold",
          "required": false
        },
        {
          "name": "sum-prop",
          "type": "string",
          "default": "",
          "usage": "Reached when the running sum of this property (or $revenue) reaches --sum-gte",
          "required": false
        },
        {
          "name": "value",
          "type": "string",
          "default": "",
          "usage": "Fixed value of reaching the goal, e.g. 4.00",
          "required": false
        },
        {
          "name": "value-from-property",
          "type": "string",
          "default": "",
          "usage": "Value from an event property (default the event's revenue)",
          "required": false
        },
        {
          "name": "where",
          "type": "string",
          "default": "",
          "usage": "Conditions on the event, \"<prop> <op> <value>\", several separated by ; (ANDed); ops: eq, neq, gt, gte, lt, lte, in, exists",
          "required": false
        },
        {
          "name": "within-days",
          "type": "string",
          "default": "",
          "usage": "Only events within this many days of --within-from",
          "required": false
        },
        {
          "name": "within-from",
          "type": "string",
          "default": "",
          "usage": "Window anchor: install, click",
          "allowed_values": [
            "install",
            "click"
          ],
          "required": false
        }
      ]
    },
    {
      "path": "p202 goal versions",
      "use": "versions <id>",
      "short": "List every version of a goal",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 import",
      "use": "import <entity> <file>",
      "short": "Import entities from JSON",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Validate import and count records without creating them",
          "required": false
        },
        {
          "name": "skip-errors",
          "type": "bool",
          "default": "false",
          "usage": "Continue importing after record-level failures; exits 5 when any record failed, and a 401 or 403 still stops it",
          "required": false
        }
      ]
    },
    {
      "path": "p202 landing-page",
      "use": "landing-page",
      "short": "Manage landing pages (pre-sell pages visitors see before the offer)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 landing-page code",
      "use": "code <id>",
      "short": "Print a landing page's tracking code (Setup > Get LP Code)",
      "long": "Prints what Setup > Get LP Code hands out for the landing page: the script to put\nabove </body> of the page visitors arrive on, and the ways out to the offer.\n\nA simple page (landing_page_type 0) links out to its own campaign: an outbound link\n(go.php?lpip=), a PHP redirect page, or a JavaScript redirect page.\nAn advanced page (landing_page_type 1) links out to each offer you name, in order:\n  --offer campaign:<id>  a campaign (`p202 campaign list`), via go.php?acip=\n  --offer rotator:<id>   a redirector (`p202 rotator list`), via go.php?rpi=\neach with its own outbound link and PHP redirect page.\n\nThe links are scheme-relative (//host/...), as the page writes them, so they work on\nan http or an https landing page. Accepts the internal landing_page_id, or the public\nid the code carries (lpip=). Needs a role with access_to_setup_section.",
      "example": "p202 landing-page code 12\n  p202 landing-page code 14 --offer campaign:3 --offer rotator:2\n  p202 landing-page code 14 --offer campaign:3,campaign:5 --json",
      "runnable": true,
      "flags": [
        {
          "name": "offer",
          "type": "stringSlice",
          "default": "[]",
          "usage": "An advanced page's offer, campaign:ID or rotator:ID; repeat the flag (or comma-separate) for each, in order",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 landing-page code",
          "ui_pages": [
            "Setup › Get LP Code"
          ],
          "phrases": [
            "landing page code",
            "landing page tracking script",
            "lp code"
          ]
        }
      ]
    },
    {
      "path": "p202 landing-page create",
      "use": "create",
      "short": "Create a new landing-page",
      "example": "p202 landing-page create --landing-page-url <landing_page_url> --aff-campaign-id <id from p202 campaign list> --landing-page-nickname <landing_page_nickname> --json",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Campaign ID (from `p202 campaign list`); 0 for an advanced landing page (--landing-page-type 1), which promotes several offers (required)",
          "required": true
        },
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        },
        {
          "name": "landing-page-nickname",
          "type": "string",
          "default": "",
          "usage": "Landing page nickname (required)",
          "required": true
        },
        {
          "name": "landing-page-type",
          "type": "string",
          "default": "",
          "usage": "Landing page type: 0 simple (one campaign), 1 advanced (several offers; --aff-campaign-id 0)",
          "required": false
        },
        {
          "name": "landing-page-url",
          "type": "string",
          "default": "",
          "usage": "Landing page URL (required)",
          "required": true
        },
        {
          "name": "leave-behind-page-url",
          "type": "string",
          "default": "",
          "usage": "Leave-behind page URL",
          "required": false
        }
      ]
    },
    {
      "path": "p202 landing-page delete",
      "use": "delete <id>",
      "short": "Delete a landing-page",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated landing-page IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 landing-page get",
      "use": "get <id>",
      "short": "Get a landing-page by ID",
      "long": "Get a landing-page by id. Accepts the internal landing_page_id (from `landing-page list`). If you pass the\npublic landing_page_id_public (the value in tracking links / the UI), it is resolved automatically;\nuse --public to force the public lookup.",
      "runnable": true,
      "flags": [
        {
          "name": "public",
          "type": "bool",
          "default": "false",
          "usage": "Treat the id as the public landing_page_id_public",
          "required": false
        }
      ]
    },
    {
      "path": "p202 landing-page list",
      "use": "list",
      "short": "List landing pages (pre-sell pages visitors see before the offer)",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by campaign ID (from `p202 campaign list`)",
          "required": false
        },
        {
          "name": "all",
          "type": "bool",
          "default": "false",
          "usage": "Fetch all rows across pages",
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "page",
          "type": "string",
          "default": "",
          "usage": "Page number",
          "required": false
        },
        {
          "name": "resolve-names",
          "type": "bool",
          "default": "false",
          "usage": "Resolve foreign key IDs to names",
          "required": false
        },
        {
          "name": "url-contains",
          "type": "string",
          "default": "",
          "usage": "Only landing-pages with a URL containing this text (case-insensitive; searches every page; fields: landing_page_url, leave_behind_page_url)",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 landing-page list",
          "ui_pages": [
            "Setup › Landing Pages"
          ]
        }
      ]
    },
    {
      "path": "p202 landing-page update",
      "use": "update <id>",
      "short": "Update a landing-page",
      "example": "p202 landing-page update <id from p202 landing-page list> --landing-page-url <new value> --json\n  (only the flags given are sent; the rest of the landing-page is unchanged)",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Campaign ID (from `p202 campaign list`); 0 for an advanced landing page (--landing-page-type 1), which promotes several offers",
          "required": false
        },
        {
          "name": "landing-page-nickname",
          "type": "string",
          "default": "",
          "usage": "Landing page nickname",
          "required": false
        },
        {
          "name": "landing-page-type",
          "type": "string",
          "default": "",
          "usage": "Landing page type: 0 simple (one campaign), 1 advanced (several offers; --aff-campaign-id 0)",
          "required": false
        },
        {
          "name": "landing-page-url",
          "type": "string",
          "default": "",
          "usage": "Landing page URL",
          "required": false
        },
        {
          "name": "leave-behind-page-url",
          "type": "string",
          "default": "",
          "usage": "Leave-behind page URL (\"\" clears it)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv",
      "use": "ltv",
      "short": "Customer lifetime value — realized LTV, per-customer detail, product/acquisition breakdowns, MRR/churn, and predictive LTV",
      "long": "Customer lifetime value: the reads (summary, customers, breakdown, cohorts, mrr, predict, abm,\nengagement, subscriptions, companies, products) and the writes the API offers — customer and\ncompany records (`ltv customer`, `ltv company`), revenue, engagement events, subscriptions and\nproducts pushed from other systems, custom fields, outbound webhooks and integrations.\n\nLTV writes cannot be staged: under --staged they are refused before anything is sent.",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 ltv abm",
      "use": "abm",
      "short": "ABM account view — companies ranked by engagement with scores, depth metrics, revenue and MRR",
      "runnable": true,
      "flags": [
        {
          "name": "company",
          "shorthand": "c",
          "type": "string",
          "default": "",
          "usage": "Drill into one company by name",
          "required": false
        },
        {
          "name": "days",
          "shorthand": "d",
          "type": "string",
          "default": "",
          "usage": "Engagement window in days (default 90, max 365)",
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Rows per page (max 500)",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv breakdown",
      "use": "breakdown",
      "short": "LTV by acquisition source (campaign, ppc_account, landing_page) or by product",
      "runnable": true,
      "flags": [
        {
          "name": "by",
          "shorthand": "b",
          "type": "string",
          "default": "",
          "usage": "Dimension: campaign, ppc_account, landing_page, product",
          "allowed_values": [
            "campaign",
            "ppc_account",
            "landing_page",
            "product"
          ],
          "required": false
        },
        {
          "name": "cf",
          "type": "stringArray",
          "default": "[]",
          "usage": "Only customers whose custom field matches: key=value, or key.min=value / key.max=value for a number or date field (repeatable, at most 3; `p202 ltv fields list` shows the keys)",
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Rows per page (max 500)",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "period",
          "shorthand": "p",
          "type": "string",
          "default": "",
          "usage": "Period: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Acquisition window start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "Acquisition window end, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv cohorts",
      "use": "cohorts",
      "short": "LTV maturation by acquisition month — each cohort's revenue by months since first seen (m0..m4, m5_plus)",
      "runnable": true,
      "flags": [
        {
          "name": "months",
          "type": "string",
          "default": "",
          "usage": "How many acquisition months, newest first (1-24, default 6)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv companies",
      "use": "companies",
      "short": "Company (ABM account) entities with live contact/revenue rollups (writes: `p202 ltv company`)",
      "runnable": true,
      "flags": [
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Rows per page (max 500)",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv company",
      "use": "company",
      "short": "Write company (ABM account) records: create, update, merge, delete (reads: `p202 ltv companies`)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 ltv company create",
      "use": "create --name <name>",
      "short": "Create a company; --domain makes customers with that email domain join it automatically",
      "runnable": true,
      "flags": [
        {
          "name": "domain",
          "type": "string",
          "default": "",
          "usage": "Email domain, e.g. acme.com: customers with it join the company automatically",
          "required": false
        },
        {
          "name": "name",
          "type": "string",
          "default": "",
          "usage": "Company name (required; unique in the account)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv company delete",
      "use": "delete <company-id>",
      "short": "Delete a company with no customers attached (one with customers is merged instead)",
      "long": "Refused while customers are attached: merge it into another company with\n`p202 ltv company merge <target> --from <id>`. --dry-run shows the company and, under\nrefused, why the delete would be turned down.",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated company IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv company merge",
      "use": "merge <target-company-id> --from <source-company-id>",
      "short": "Merge one company into another: its customers move to the target and it is deleted (irreversible)",
      "long": "Moves every customer of --from onto the target, gives the target --from's domain when it has\nnone, and deletes --from. It cannot be undone, so it asks first; --force skips the question.\n\n  p202 ltv company merge 3 --from 9",
      "runnable": true,
      "flags": [
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip the confirmation prompt",
          "required": false
        },
        {
          "name": "from",
          "type": "string",
          "default": "",
          "usage": "The company merged INTO the target and deleted (required)",
          "required": true
        }
      ]
    },
    {
      "path": "p202 ltv company update",
      "use": "update <company-id>",
      "short": "Rename a company or change its auto-attach domain (--domain \"\" clears it)",
      "runnable": true,
      "flags": [
        {
          "name": "domain",
          "type": "string",
          "default": "",
          "usage": "New auto-attach domain (\"\" clears it)",
          "required": false
        },
        {
          "name": "name",
          "type": "string",
          "default": "",
          "usage": "New name",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv customer",
      "use": "customer",
      "short": "Write customer records: upsert, update, merge, erase (anonymize), aliases (reads: `p202 ltv customers`)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 ltv customer alias",
      "use": "alias",
      "short": "Map another identifier (email hash, ESP id, merchant id, subid) to a customer, or remove one",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 ltv customer alias add",
      "use": "add <customer-id> --value <identifier>",
      "short": "Add an identifier that resolves to this customer from then on",
      "long": "Later events carrying this identifier resolve to the customer. An identifier that already\nbelongs to another customer is refused (the two records are one person: merge them).\n\n  p202 ltv customer alias add 42 --type esp_id --value 48213",
      "runnable": true,
      "flags": [
        {
          "name": "type",
          "type": "string",
          "default": "",
          "usage": "What kind of identifier (default custom): email_md5, email_sha256, esp_id, merchant_id, subid, custom",
          "allowed_values": [
            "email_md5",
            "email_sha256",
            "esp_id",
            "merchant_id",
            "subid",
            "custom"
          ],
          "required": false
        },
        {
          "name": "value",
          "type": "string",
          "default": "",
          "usage": "The identifier (required); email_md5/email_sha256 take the hex digest",
          "required": true
        }
      ]
    },
    {
      "path": "p202 ltv customer alias remove",
      "use": "remove <customer-id> <alias-id>",
      "short": "Remove one identifier from a customer (the customer and its revenue stay)",
      "long": "Only the mapping goes: a later event carrying the identifier no longer resolves to this\ncustomer. Alias ids are in `p202 ltv customers <customer-id>` (aliases[].alias_id).\n\n  p202 ltv customer alias remove 42 7 --dry-run",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated alias IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv customer erase",
      "use": "erase <customer-id>",
      "short": "Erase a customer's personal data (GDPR-style): CRM fields, aliases and field values go, revenue history stays",
      "long": "Anonymizes the customer: name, email, phone, company, address, aliases (and their identity-graph\nsignals), custom field values and personalization tokens are removed, the reference becomes\nerased:<id> and the status anonymized. The customer row and its revenue events and subscriptions\nare kept, so LTV totals do not change. Not reversible: it asks first (--force skips the\nquestion), and --dry-run shows what would be removed and what kept.\n\n  p202 ltv customer erase 42 --dry-run\n  p202 ltv customer erase 42 --force",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated customer IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv customer merge",
      "use": "merge <target-customer-id> --from <source-customer-id>",
      "short": "Merge one customer into another: the source's aliases, revenue, subscriptions and fields move to the target (irreversible)",
      "long": "Moves everything of --from (aliases, revenue events, conversions, subscriptions, custom field\nvalues, engagement) onto the target, recomputes the target's totals, and retires the source\n(it points at the target from then on). The target's own custom field values win a conflict.\nIt cannot be undone, so it asks first; --force skips the question.\n\n  p202 ltv customer merge 42 --from 57",
      "runnable": true,
      "flags": [
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip the confirmation prompt",
          "required": false
        },
        {
          "name": "from",
          "type": "string",
          "default": "",
          "usage": "The customer merged INTO the target and retired (required)",
          "required": true
        }
      ]
    },
    {
      "path": "p202 ltv customer update",
      "use": "update <customer-id>",
      "short": "Change a customer's CRM fields, custom fields or aliases (a flag given empty clears that field)",
      "long": "Changes only what the flags name. A flag given empty clears that field (--phone \"\");\n--field key= clears a custom field; a flag not given is not sent.\n\n  p202 ltv customer update 42 --email ada@example.com --phone \"\" --field plan=pro",
      "runnable": true,
      "flags": [
        {
          "name": "address-line1",
          "type": "string",
          "default": "",
          "usage": "Address line 1 (\"\" clears it)",
          "required": false
        },
        {
          "name": "address-line2",
          "type": "string",
          "default": "",
          "usage": "Address line 2 (\"\" clears it)",
          "required": false
        },
        {
          "name": "alias",
          "type": "stringArray",
          "default": "[]",
          "usage": "Another identifier for this customer, type=value (repeatable; type is one of email_md5, email_sha256, esp_id, merchant_id, subid, custom)",
          "required": false
        },
        {
          "name": "city",
          "type": "string",
          "default": "",
          "usage": "City (\"\" clears it)",
          "required": false
        },
        {
          "name": "company",
          "type": "string",
          "default": "",
          "usage": "Company: attaches the customer to that company (created if new); \"\" detaches (\"\" clears it)",
          "required": false
        },
        {
          "name": "country",
          "type": "string",
          "default": "",
          "usage": "Country (\"\" clears it)",
          "required": false
        },
        {
          "name": "email",
          "type": "string",
          "default": "",
          "usage": "Email address (\"\" clears it)",
          "required": false
        },
        {
          "name": "field",
          "type": "stringArray",
          "default": "[]",
          "usage": "A custom field value, key=value (repeatable; key= with nothing after = clears it; `p202 ltv fields list` shows the keys)",
          "required": false
        },
        {
          "name": "first-name",
          "type": "string",
          "default": "",
          "usage": "First name (\"\" clears it)",
          "required": false
        },
        {
          "name": "last-name",
          "type": "string",
          "default": "",
          "usage": "Last name (\"\" clears it)",
          "required": false
        },
        {
          "name": "phone",
          "type": "string",
          "default": "",
          "usage": "Phone (\"\" clears it)",
          "required": false
        },
        {
          "name": "postal-code",
          "type": "string",
          "default": "",
          "usage": "Postal code (\"\" clears it)",
          "required": false
        },
        {
          "name": "region",
          "type": "string",
          "default": "",
          "usage": "Region or state (\"\" clears it)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv customer upsert",
      "use": "upsert",
      "short": "Create or update a customer by --customer-ref (your id) or --customer-id",
      "long": "Finds the customer by --customer-id, or by --customer-ref (+ --customer-ref-type), creating one\nwhen no customer has that reference, then applies the record flags in one transaction.\nA record flag given empty clears that field; a flag not given leaves it as it is.\n\n  p202 ltv customer upsert --customer-ref ORD-CUST-77 --email ada@example.com --first-name Ada\n  p202 ltv customer upsert --customer-ref 9f1c… --customer-ref-type email_md5 --field plan=pro",
      "runnable": true,
      "flags": [
        {
          "name": "address-line1",
          "type": "string",
          "default": "",
          "usage": "Address line 1 (\"\" clears it)",
          "required": false
        },
        {
          "name": "address-line2",
          "type": "string",
          "default": "",
          "usage": "Address line 2 (\"\" clears it)",
          "required": false
        },
        {
          "name": "alias",
          "type": "stringArray",
          "default": "[]",
          "usage": "Another identifier for this customer, type=value (repeatable; type is one of email_md5, email_sha256, esp_id, merchant_id, subid, custom)",
          "required": false
        },
        {
          "name": "city",
          "type": "string",
          "default": "",
          "usage": "City (\"\" clears it)",
          "required": false
        },
        {
          "name": "company",
          "type": "string",
          "default": "",
          "usage": "Company: attaches the customer to that company (created if new); \"\" detaches (\"\" clears it)",
          "required": false
        },
        {
          "name": "country",
          "type": "string",
          "default": "",
          "usage": "Country (\"\" clears it)",
          "required": false
        },
        {
          "name": "customer-id",
          "type": "string",
          "default": "",
          "usage": "The customer's internal id (`p202 ltv customers`)",
          "required": false
        },
        {
          "name": "customer-ref",
          "type": "string",
          "default": "",
          "usage": "Your system's id for the customer; the server finds it, or creates a customer for it",
          "required": false
        },
        {
          "name": "customer-ref-type",
          "type": "string",
          "default": "",
          "usage": "What kind of reference --customer-ref is (default custom): email_md5, email_sha256, esp_id, merchant_id, subid, custom",
          "allowed_values": [
            "email_md5",
            "email_sha256",
            "esp_id",
            "merchant_id",
            "subid",
            "custom"
          ],
          "required": false
        },
        {
          "name": "email",
          "type": "string",
          "default": "",
          "usage": "Email address (\"\" clears it)",
          "required": false
        },
        {
          "name": "field",
          "type": "stringArray",
          "default": "[]",
          "usage": "A custom field value, key=value (repeatable; key= with nothing after = clears it; `p202 ltv fields list` shows the keys)",
          "required": false
        },
        {
          "name": "first-name",
          "type": "string",
          "default": "",
          "usage": "First name (\"\" clears it)",
          "required": false
        },
        {
          "name": "last-name",
          "type": "string",
          "default": "",
          "usage": "Last name (\"\" clears it)",
          "required": false
        },
        {
          "name": "phone",
          "type": "string",
          "default": "",
          "usage": "Phone (\"\" clears it)",
          "required": false
        },
        {
          "name": "postal-code",
          "type": "string",
          "default": "",
          "usage": "Postal code (\"\" clears it)",
          "required": false
        },
        {
          "name": "region",
          "type": "string",
          "default": "",
          "usage": "Region or state (\"\" clears it)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv customers",
      "use": "customers [id]",
      "short": "List customers with LTV rollups, or show one customer in full (CRM, aliases, custom fields, recent revenue)",
      "long": "List customers with their LTV rollups, newest-valued first, or show one in full.\n\n  p202 ltv customers --search acme --segment repeat\n  p202 ltv customers --cf plan=pro --cf score.min=50 --all\n  p202 ltv customers 42\n\n--search matches the customer reference, email, company or name. --cf filters by custom\nfield: key=value, or key.min/key.max for number and date fields (at most 3). Writes are\n`p202 ltv customer` (upsert, update, merge, erase, alias).",
      "runnable": true,
      "flags": [
        {
          "name": "all",
          "type": "bool",
          "default": "false",
          "usage": "Fetch every page (500 rows a request)",
          "required": false
        },
        {
          "name": "cf",
          "type": "stringArray",
          "default": "[]",
          "usage": "Only customers whose custom field matches: key=value, or key.min=value / key.max=value for a number or date field (repeatable, at most 3; `p202 ltv fields list` shows the keys)",
          "required": false
        },
        {
          "name": "dir",
          "type": "string",
          "default": "",
          "usage": "Sort direction: ASC, DESC",
          "allowed_values": [
            "ASC",
            "DESC"
          ],
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Rows per page (max 500)",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "period",
          "shorthand": "p",
          "type": "string",
          "default": "",
          "usage": "Period: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "search",
          "type": "string",
          "default": "",
          "usage": "Only customers whose reference, email, company or name contains this text (the API's q)",
          "required": false
        },
        {
          "name": "segment",
          "type": "string",
          "default": "",
          "usage": "Only this segment (repeat: 2+ orders; subscribers: an active subscription; at_risk: a past_due subscription): repeat, subscribers, at_risk",
          "allowed_values": [
            "repeat",
            "subscribers",
            "at_risk"
          ],
          "required": false
        },
        {
          "name": "sort",
          "shorthand": "s",
          "type": "string",
          "default": "",
          "usage": "Sort: total_revenue, order_count, last_activity_time, first_seen_time, mrr",
          "allowed_values": [
            "total_revenue",
            "order_count",
            "last_activity_time",
            "first_seen_time",
            "mrr"
          ],
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Acquisition window start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "Acquisition window end, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv engagement",
      "use": "engagement <customer-id>",
      "short": "One customer's engagement — browsing, instrumented events, and the suggested next offer",
      "runnable": true,
      "flags": [
        {
          "name": "days",
          "shorthand": "d",
          "type": "string",
          "default": "",
          "usage": "Engagement window in days (default 90, max 365)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv engagement-event",
      "use": "engagement-event",
      "short": "Record server-side ABM engagement events on a customer (not `p202 event send`, which reports a click's web events to its goals)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 ltv engagement-event record",
      "use": "record --event <name> (--customer-ref <id> | --customer-id <id>)",
      "short": "Record an engagement event (demo_requested, pricing_viewed, …) on a customer for the ABM and engagement views",
      "long": "Adds one event to the customer's engagement history (`p202 ltv engagement <id>`, `p202 ltv abm`).\nIt is not a conversion and pays nothing; a click's web events for its goals go through\n`p202 event send`.\n\n  p202 ltv engagement-event record --customer-ref CUST-77 --event demo_requested",
      "runnable": true,
      "flags": [
        {
          "name": "customer-crm",
          "type": "string",
          "default": "",
          "usage": "CRM fields as a JSON object, applied only when this call creates the customer, e.g. '{\"email\":\"a@b.co\",\"first_name\":\"Ada\"}'",
          "required": false
        },
        {
          "name": "customer-id",
          "type": "string",
          "default": "",
          "usage": "The customer's internal id (`p202 ltv customers`)",
          "required": false
        },
        {
          "name": "customer-ref",
          "type": "string",
          "default": "",
          "usage": "Your system's id for the customer; the server finds it, or creates a customer for it",
          "required": false
        },
        {
          "name": "customer-ref-type",
          "type": "string",
          "default": "",
          "usage": "What kind of reference --customer-ref is (default custom): email_md5, email_sha256, esp_id, merchant_id, subid, custom",
          "allowed_values": [
            "email_md5",
            "email_sha256",
            "esp_id",
            "merchant_id",
            "subid",
            "custom"
          ],
          "required": false
        },
        {
          "name": "event",
          "type": "string",
          "default": "",
          "usage": "The event's name, e.g. demo_requested (required)",
          "required": true
        },
        {
          "name": "occurred-at",
          "type": "string",
          "default": "",
          "usage": "When it happened, unix seconds (default now)",
          "required": false
        },
        {
          "name": "value",
          "type": "string",
          "default": "",
          "usage": "A number that goes with it: seconds, a percentage, a score",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv fields",
      "use": "fields",
      "short": "Customer custom-field definitions: list, create, update, delete",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 ltv fields create",
      "use": "create --key <key>",
      "short": "Define a custom field customers can carry (filter by it with --cf)",
      "long": "Defines a field: its key (how writes and --cf filters name it), label, type, and for a select\nfield its choices. The key and type cannot change later.\n\n  p202 ltv fields create --key plan --type select --option free --option pro\n  p202 ltv fields create --key score --type number --label \"Lead score\"",
      "runnable": true,
      "flags": [
        {
          "name": "key",
          "type": "string",
          "default": "",
          "usage": "The field's key: 1-64 of a-z, 0-9 and _ (required; fixed once created)",
          "required": false
        },
        {
          "name": "label",
          "type": "string",
          "default": "",
          "usage": "Display label (default the key)",
          "required": false
        },
        {
          "name": "option",
          "type": "stringArray",
          "default": "[]",
          "usage": "A select field's choice (repeatable; required for --type select)",
          "required": false
        },
        {
          "name": "required",
          "type": "bool",
          "default": "false",
          "usage": "Every customer save must carry a value for it",
          "required": false
        },
        {
          "name": "sort-order",
          "type": "string",
          "default": "",
          "usage": "Position among the fields (0 or more; default 0)",
          "required": false
        },
        {
          "name": "type",
          "type": "string",
          "default": "",
          "usage": "Value type (default text; fixed once created): text, number, date, boolean, select, email, url",
          "allowed_values": [
            "text",
            "number",
            "date",
            "boolean",
            "select",
            "email",
            "url"
          ],
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv fields delete",
      "use": "delete <field-id>",
      "short": "Delete a custom field and every customer's value for it",
      "long": "--dry-run shows the field and how many customers' values go with it.\n\n  p202 ltv fields delete 3 --dry-run",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated field IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv fields list",
      "use": "list",
      "short": "List the account's custom fields (key, type, options, required)",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 ltv fields update",
      "use": "update <field-id>",
      "short": "Change a field's label, select choices, required flag or order (key and type are fixed)",
      "long": "Prints the account's fields afterwards. --required=false makes a required field optional.\n\n  p202 ltv fields update 3 --label \"Plan tier\" --option free --option pro --option enterprise",
      "runnable": true,
      "flags": [
        {
          "name": "label",
          "type": "string",
          "default": "",
          "usage": "New display label",
          "required": false
        },
        {
          "name": "option",
          "type": "stringArray",
          "default": "[]",
          "usage": "A select field's choice (repeatable; the full new list replaces the old)",
          "required": false
        },
        {
          "name": "required",
          "type": "bool",
          "default": "false",
          "usage": "Make it required (--required=false makes it optional)",
          "required": false
        },
        {
          "name": "sort-order",
          "type": "string",
          "default": "",
          "usage": "New position among the fields (0 or more)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv integrations",
      "use": "integrations",
      "short": "Inbound integration records (an ESP, membership or billing system pushing LTV data): list, create, delete",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 ltv integrations create",
      "use": "create --provider <name>",
      "short": "Record an integration: its provider, a name, and provider settings as a JSON object",
      "long": "p202 ltv integrations create --provider klaviyo --name \"Main list\" --config '{\"list_id\":\"XyZ\"}'\n  p202 ltv integrations create --provider stripe --config-file stripe.json",
      "runnable": true,
      "flags": [
        {
          "name": "config",
          "type": "string",
          "default": "",
          "usage": "Provider settings as a JSON object, e.g. '{\"list_id\":\"XyZ\"}'",
          "required": false
        },
        {
          "name": "config-file",
          "type": "string",
          "default": "",
          "usage": "Provider settings as a JSON object in a file (- for stdin)",
          "required": false
        },
        {
          "name": "name",
          "type": "string",
          "default": "",
          "usage": "A name for it (default the provider)",
          "required": false
        },
        {
          "name": "provider",
          "type": "string",
          "default": "",
          "usage": "The system: lowercase a-z, 0-9, - and _ (required)",
          "required": true
        }
      ]
    },
    {
      "path": "p202 ltv integrations delete",
      "use": "delete <integration-id>",
      "short": "Delete an integration record",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated integration IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv integrations list",
      "use": "list",
      "short": "List the account's integration records with their config",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 ltv mrr",
      "use": "mrr",
      "short": "Subscription economics — active MRR/ARR, status counts, monthly churn with its inputs",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 ltv next-offer",
      "use": "next-offer",
      "short": "Report that you delivered a customer's next-offer recommendation (read it with `p202 ltv engagement`)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 ltv next-offer impression",
      "use": "impression <customer-id>",
      "short": "Log that the customer was shown an offer (an email send, an external CRM), for the fatigue rule",
      "long": "Records that the offer reached the customer through a channel the tracker cannot see. Without\n--campaign-id the customer's current recommendation is recorded (`p202 ltv engagement <id>`\nshows it); when there is none, pass the campaign you delivered.\n\n  p202 ltv next-offer impression 42 --campaign-id 7",
      "runnable": true,
      "flags": [
        {
          "name": "campaign-id",
          "type": "string",
          "default": "",
          "usage": "The campaign you delivered (default the current recommendation)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv predict",
      "use": "predict",
      "short": "Predictive LTV — deterministic projection with guards; every number ships with its inputs",
      "runnable": true,
      "flags": [
        {
          "name": "by",
          "shorthand": "b",
          "type": "string",
          "default": "",
          "usage": "Also project per cohort: campaign, ppc_account, landing_page, product",
          "allowed_values": [
            "campaign",
            "ppc_account",
            "landing_page",
            "product"
          ],
          "required": false
        },
        {
          "name": "cf",
          "type": "stringArray",
          "default": "[]",
          "usage": "Only customers whose custom field matches: key=value, or key.min=value / key.max=value for a number or date field (repeatable, at most 3; `p202 ltv fields list` shows the keys)",
          "required": false
        },
        {
          "name": "period",
          "shorthand": "p",
          "type": "string",
          "default": "",
          "usage": "Period: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Acquisition window start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "Acquisition window end, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv product",
      "use": "product",
      "short": "Catalog products: upsert by your product id, update or delete by id (reads: `p202 ltv products`)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 ltv product delete",
      "use": "delete <product-id>",
      "short": "Delete a catalog product no order line item names (refused while one does)",
      "long": "--dry-run shows the product and, as refused, why the delete would be refused.\n\n  p202 ltv product delete 12 --dry-run",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated product IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv product update",
      "use": "update <product-id>",
      "short": "Edit a catalog product's name, sku or list price by its id (the LTV Products tab's Edit)",
      "long": "Changes only the fields given. The name cannot be blank; --sku \"\" and --price \"\" clear them.\nPast order line items keep the name they were sold under. The external product id is the\nproduct's key and does not change (`ltv product upsert` writes by it).\n\n  p202 ltv product update 12 --name \"Pro plan (annual)\" --price 490\n  p202 ltv product update 12 --sku \"\"",
      "runnable": true,
      "flags": [
        {
          "name": "name",
          "type": "string",
          "default": "",
          "usage": "New product name (cannot be blank)",
          "required": false
        },
        {
          "name": "price",
          "type": "string",
          "default": "",
          "usage": "New list price in the account currency (\"\" clears it)",
          "required": false
        },
        {
          "name": "sku",
          "type": "string",
          "default": "",
          "usage": "New SKU (\"\" clears it)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv product upsert",
      "use": "upsert (--external-product-id <id> | --sku <sku>)",
      "short": "Create or update a product keyed by your product id (or sku); revenue line items name it the same way",
      "long": "Keyed by --external-product-id, or by --sku when there is none. A field not given keeps its\nstored value.\n\n  p202 ltv product upsert --sku PRO-1 --name \"Pro plan\" --price 49",
      "runnable": true,
      "flags": [
        {
          "name": "external-product-id",
          "type": "string",
          "default": "",
          "usage": "Your product id (the key)",
          "required": false
        },
        {
          "name": "name",
          "type": "string",
          "default": "",
          "usage": "Product name",
          "required": false
        },
        {
          "name": "price",
          "type": "string",
          "default": "",
          "usage": "List price in the account currency",
          "required": false
        },
        {
          "name": "sku",
          "type": "string",
          "default": "",
          "usage": "SKU (the key when there is no --external-product-id)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv products",
      "use": "products",
      "short": "The product catalog revenue line items and `ltv product upsert` write to, newest first",
      "runnable": true,
      "flags": [
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Rows per page (max 500)",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv revenue",
      "use": "revenue",
      "short": "Record clickless revenue (an ESP order, a membership charge) on a customer's ledger",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 ltv revenue record",
      "use": "record --amount <n> (--customer-ref <id> | --customer-id <id>)",
      "short": "Record a purchase, one-time charge, refund, chargeback or adjustment on a customer",
      "long": "Appends one event to the customer's revenue ledger (source api) and updates their totals.\nRefunds and chargebacks are sent positive and stored negative; a negative amount is only an\nadjustment. Renewals go through `p202 ltv subscription event`. --idempotency-key makes a retry\nsafe: the same request again records nothing and answers with the first event (duplicate:\ntrue). A different request under a used key (another amount, customer, items, ...) is refused\nnaming idempotency_key and what differs, and records nothing: a different event needs its own key.\n\n  p202 ltv revenue record --customer-ref CUST-77 --amount 49.00 --idempotency-key ORD-1001 \\\n      --item '{\"sku\":\"PRO-1\",\"quantity\":1,\"unit_price\":49}'",
      "runnable": true,
      "flags": [
        {
          "name": "amount",
          "type": "string",
          "default": "",
          "usage": "The amount, in the account currency (required)",
          "required": true
        },
        {
          "name": "currency",
          "type": "string",
          "default": "",
          "usage": "Currency code; must be the account currency (default it)",
          "required": false
        },
        {
          "name": "customer-crm",
          "type": "string",
          "default": "",
          "usage": "CRM fields as a JSON object, applied only when this call creates the customer, e.g. '{\"email\":\"a@b.co\",\"first_name\":\"Ada\"}'",
          "required": false
        },
        {
          "name": "customer-id",
          "type": "string",
          "default": "",
          "usage": "The customer's internal id (`p202 ltv customers`)",
          "required": false
        },
        {
          "name": "customer-ref",
          "type": "string",
          "default": "",
          "usage": "Your system's id for the customer; the server finds it, or creates a customer for it",
          "required": false
        },
        {
          "name": "customer-ref-type",
          "type": "string",
          "default": "",
          "usage": "What kind of reference --customer-ref is (default custom): email_md5, email_sha256, esp_id, merchant_id, subid, custom",
          "allowed_values": [
            "email_md5",
            "email_sha256",
            "esp_id",
            "merchant_id",
            "subid",
            "custom"
          ],
          "required": false
        },
        {
          "name": "event-type",
          "type": "string",
          "default": "",
          "usage": "What it is (default purchase): purchase, one_time, refund, chargeback, adjustment",
          "allowed_values": [
            "purchase",
            "one_time",
            "refund",
            "chargeback",
            "adjustment"
          ],
          "required": false
        },
        {
          "name": "external-ref",
          "type": "string",
          "default": "",
          "usage": "Your reference for the event (an order number)",
          "required": false
        },
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Your id for this event: the same request again records nothing and answers with the first event; a different one under it is refused",
          "required": false
        },
        {
          "name": "item",
          "type": "stringArray",
          "default": "[]",
          "usage": "A line item as a JSON object (repeatable), e.g. '{\"sku\":\"PRO-1\",\"name\":\"Pro plan\",\"quantity\":1,\"unit_price\":49}'",
          "required": false
        },
        {
          "name": "items-file",
          "type": "string",
          "default": "",
          "usage": "Line items as a JSON array in a file (- for stdin), instead of --item",
          "required": false
        },
        {
          "name": "occurred-at",
          "type": "string",
          "default": "",
          "usage": "When it happened, unix seconds (default now)",
          "required": false
        },
        {
          "name": "transaction-id",
          "type": "string",
          "default": "",
          "usage": "The payment's transaction id",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv subscription",
      "use": "subscription",
      "short": "Create or update a subscription, and record its renewals, refunds and cancellation (reads: `p202 ltv subscriptions`)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 ltv subscription event",
      "use": "event <external-sub-id> --type renewal|cancel|refund",
      "short": "Record a subscription's renewal (extends it, adds revenue), refund (negative revenue) or cancellation",
      "long": "renewal adds a renewal to the ledger (the subscription's amount unless --amount), extends the\npaid-through period and reactivates it; refund adds negative revenue; cancel marks it canceled\nand moves no money. --idempotency-key (or --transaction-id) makes a retried renewal or refund\nsafe; a repeat answers changed: false. A different amount, time or transaction id under a used\nkey is refused, naming the key, and records nothing.\n\n  p202 ltv subscription event sub_123 --type renewal --transaction-id ch_889",
      "runnable": true,
      "flags": [
        {
          "name": "amount",
          "type": "string",
          "default": "",
          "usage": "Renewal or refund amount (default the subscription's amount)",
          "required": false
        },
        {
          "name": "currency",
          "type": "string",
          "default": "",
          "usage": "Currency code; must be the account currency (default it)",
          "required": false
        },
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Your id for this renewal or refund: the same request again records nothing; a different one under it is refused",
          "required": false
        },
        {
          "name": "occurred-at",
          "type": "string",
          "default": "",
          "usage": "When it happened, unix seconds (default now)",
          "required": false
        },
        {
          "name": "period-end",
          "type": "string",
          "default": "",
          "usage": "Renewal only: the new paid-through time, unix seconds (default one interval on)",
          "required": false
        },
        {
          "name": "transaction-id",
          "type": "string",
          "default": "",
          "usage": "The payment's transaction id (also makes a retry safe when there is no key)",
          "required": false
        },
        {
          "name": "type",
          "type": "string",
          "default": "",
          "usage": "What happened (required): renewal, cancel, refund",
          "allowed_values": [
            "renewal",
            "cancel",
            "refund"
          ],
          "required": true
        }
      ]
    },
    {
      "path": "p202 ltv subscription upsert",
      "use": "upsert --external-sub-id <id> --amount <n> (--customer-ref <id> | --customer-id <id>)",
      "short": "Create or update a subscription keyed by your billing system's id; MRR follows from amount and interval",
      "long": "Keyed by --external-sub-id: the same id again updates it (and may move it to another customer).\nMRR is the amount normalized to a month (a trial carries none).\n\n  p202 ltv subscription upsert --external-sub-id sub_123 --customer-ref CUST-77 --amount 29 --interval month",
      "runnable": true,
      "flags": [
        {
          "name": "amount",
          "type": "string",
          "default": "",
          "usage": "What one billing interval charges (required)",
          "required": true
        },
        {
          "name": "currency",
          "type": "string",
          "default": "",
          "usage": "Currency code; must be the account currency (default it)",
          "required": false
        },
        {
          "name": "customer-crm",
          "type": "string",
          "default": "",
          "usage": "CRM fields as a JSON object, applied only when this call creates the customer, e.g. '{\"email\":\"a@b.co\",\"first_name\":\"Ada\"}'",
          "required": false
        },
        {
          "name": "customer-id",
          "type": "string",
          "default": "",
          "usage": "The customer's internal id (`p202 ltv customers`)",
          "required": false
        },
        {
          "name": "customer-ref",
          "type": "string",
          "default": "",
          "usage": "Your system's id for the customer; the server finds it, or creates a customer for it",
          "required": false
        },
        {
          "name": "customer-ref-type",
          "type": "string",
          "default": "",
          "usage": "What kind of reference --customer-ref is (default custom): email_md5, email_sha256, esp_id, merchant_id, subid, custom",
          "allowed_values": [
            "email_md5",
            "email_sha256",
            "esp_id",
            "merchant_id",
            "subid",
            "custom"
          ],
          "required": false
        },
        {
          "name": "external-sub-id",
          "type": "string",
          "default": "",
          "usage": "Your billing system's subscription id (required)",
          "required": true
        },
        {
          "name": "grace-days",
          "type": "string",
          "default": "",
          "usage": "Days past the period end before it counts as past_due (default 3)",
          "required": false
        },
        {
          "name": "interval",
          "type": "string",
          "default": "",
          "usage": "Billing interval (default month): day, week, month, year",
          "allowed_values": [
            "day",
            "week",
            "month",
            "year"
          ],
          "required": false
        },
        {
          "name": "interval-count",
          "type": "string",
          "default": "",
          "usage": "Intervals per charge, e.g. 3 with --interval month for quarterly (default 1)",
          "required": false
        },
        {
          "name": "period-end",
          "type": "string",
          "default": "",
          "usage": "Current period end, unix seconds (default one interval after the start)",
          "required": false
        },
        {
          "name": "period-start",
          "type": "string",
          "default": "",
          "usage": "Current period start, unix seconds (default --started-at)",
          "required": false
        },
        {
          "name": "plan-name",
          "type": "string",
          "default": "",
          "usage": "Plan name",
          "required": false
        },
        {
          "name": "started-at",
          "type": "string",
          "default": "",
          "usage": "When it started, unix seconds (default now)",
          "required": false
        },
        {
          "name": "status",
          "type": "string",
          "default": "",
          "usage": "Lifecycle status (default active): trialing, active, past_due, paused, canceled",
          "allowed_values": [
            "trialing",
            "active",
            "past_due",
            "paused",
            "canceled"
          ],
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv subscriptions",
      "use": "subscriptions",
      "short": "Account-wide subscription list joined to customers, filterable by lifecycle status",
      "runnable": true,
      "flags": [
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Rows per page (max 500)",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "status",
          "shorthand": "s",
          "type": "string",
          "default": "",
          "usage": "Only this status: trialing, active, past_due, paused, canceled",
          "allowed_values": [
            "trialing",
            "active",
            "past_due",
            "paused",
            "canceled"
          ],
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv summary",
      "use": "summary",
      "short": "Realized LTV totals — customers, revenue, avg LTV, AOV, repeat rate, MRR",
      "runnable": true,
      "flags": [
        {
          "name": "cf",
          "type": "stringArray",
          "default": "[]",
          "usage": "Only customers whose custom field matches: key=value, or key.min=value / key.max=value for a number or date field (repeatable, at most 3; `p202 ltv fields list` shows the keys)",
          "required": false
        },
        {
          "name": "period",
          "shorthand": "p",
          "type": "string",
          "default": "",
          "usage": "Period: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Acquisition window start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "Acquisition window end, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 ltv summary",
          "ui_pages": [
            "Analyze › Customer LTV"
          ],
          "phrases": [
            "customer lifetime value"
          ]
        }
      ]
    },
    {
      "path": "p202 ltv webhooks",
      "use": "webhooks",
      "short": "Outbound LTV webhooks (customer, revenue, subscription, conversion, engagement events): list, create, deliveries, delete",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 ltv webhooks create",
      "use": "create --url https://…",
      "short": "Register an endpoint for signed LTV events; the response holds its secret, shown this once",
      "long": "Deliveries are signed: X-P202-Signature is sha256=HMAC-SHA256(body, secret). The secret is in\nthis command's output and nowhere else, ever: store it now. --events chooses what is sent\n(default every event this version sends; * also takes events later versions add).\nThe URL must be https and must not point at a private, loopback or metadata address.\n\n  p202 ltv webhooks create --url https://hooks.example.com/p202 --events revenue.recorded,subscription.changed",
      "runnable": true,
      "flags": [
        {
          "name": "events",
          "type": "string",
          "default": "",
          "usage": "Events to send, comma-separated (default every event): customer.updated, revenue.recorded, subscription.changed, conversion.recorded, engagement.recorded, *; comma-separated for several",
          "allowed_values": [
            "customer.updated",
            "revenue.recorded",
            "subscription.changed",
            "conversion.recorded",
            "engagement.recorded",
            "*"
          ],
          "value_list": true,
          "required": false
        },
        {
          "name": "url",
          "type": "string",
          "default": "",
          "usage": "The https endpoint to deliver to (required)",
          "required": true
        }
      ]
    },
    {
      "path": "p202 ltv webhooks delete",
      "use": "delete <webhook-id>",
      "short": "Delete a webhook and its delivery queue (pending deliveries are dropped, not sent)",
      "long": "--dry-run shows the webhook and how many deliveries, by status, go with it.",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated webhook IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv webhooks deliveries",
      "use": "deliveries <webhook-id>",
      "short": "A webhook's delivery log, newest first: each event's status, attempts, next retry and last response or error",
      "long": "What the LTV Settings tab's Log shows (its last 25 by default; --limit up to 100), and the last\nattempt's response body or error (\"curl: …\", \"blocked: …\", stored cut to 1,000 bytes). A\ndelivery is retried with backoff and fails after max_attempts (6), which marks the webhook\ndead. Never the secret, and not the payload.\n\n  p202 ltv webhooks deliveries 3 --status failed",
      "runnable": true,
      "flags": [
        {
          "name": "limit",
          "type": "string",
          "default": "",
          "usage": "How many deliveries to list, 1-100 (default 25)",
          "required": false
        },
        {
          "name": "status",
          "type": "string",
          "default": "",
          "usage": "Only deliveries in this state: pending, delivered, failed",
          "allowed_values": [
            "pending",
            "delivered",
            "failed"
          ],
          "required": false
        }
      ]
    },
    {
      "path": "p202 ltv webhooks list",
      "use": "list",
      "short": "List the account's LTV webhooks (the secrets are never shown again)",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 ppc-account",
      "use": "ppc-account",
      "aliases": [
        "traffic-source"
      ],
      "short": "Manage traffic sources (PPC accounts)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 ppc-account create",
      "use": "create",
      "short": "Create a new ppc-account",
      "example": "p202 ppc-account create --ppc-account-name <account_name> --ppc-network-id <id from p202 ppc-network list> --json",
      "runnable": true,
      "flags": [
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        },
        {
          "name": "ppc-account-default",
          "type": "string",
          "default": "",
          "usage": "Set as default account (1) or not (0): 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "ppc-account-name",
          "type": "string",
          "default": "",
          "usage": "Account name (required)",
          "required": true
        },
        {
          "name": "ppc-network-id",
          "type": "string",
          "default": "",
          "usage": "PPC network ID (from `p202 ppc-network list`) (required)",
          "required": true
        }
      ]
    },
    {
      "path": "p202 ppc-account delete",
      "use": "delete <id>",
      "short": "Delete a ppc-account",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated ppc-account IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ppc-account get",
      "use": "get <id>",
      "short": "Get a ppc-account by ID",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 ppc-account list",
      "use": "list",
      "short": "List traffic sources (PPC accounts)",
      "runnable": true,
      "flags": [
        {
          "name": "all",
          "type": "bool",
          "default": "false",
          "usage": "Fetch all rows across pages",
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "page",
          "type": "string",
          "default": "",
          "usage": "Page number",
          "required": false
        },
        {
          "name": "ppc-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC network ID (from `p202 ppc-network list`)",
          "required": false
        },
        {
          "name": "resolve-names",
          "type": "bool",
          "default": "false",
          "usage": "Resolve foreign key IDs to names",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 ppc-account list",
          "phrases": [
            "traffic source accounts",
            "ad accounts"
          ]
        }
      ]
    },
    {
      "path": "p202 ppc-account pixel",
      "use": "pixel",
      "aliases": [
        "pixels"
      ],
      "short": "Manage the pixels a traffic source account fires on a conversion",
      "long": "An account's pixels report its conversions back to the traffic source. Types\n(--type-id): 1 Image, 2 Iframe, 3 Javascript, 4 Postback (server to server),\n5 Raw (markup as given), 6 Bot202 Facebook Pixel Assistant. For every type except\nRaw the code is the URL (several separated by spaces), with tokens such as\n[[subid]], [[payout]] or [[transactionid]] filled in when it fires.\n\nA Postback pixel can also take a correction URL (--correction-url), where corrections\ngo when a conversion it announced is replaced; one per code URL, in the same order.\n\nSetup > Traffic Sources > an account's Advanced edits the same pixels. Needs a role\nwith access_to_setup_section and a key with ppc-accounts scope.",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 ppc-account pixel create",
      "use": "create <ppc_account_id>",
      "short": "Add a pixel to a traffic source account",
      "example": "p202 ppc-account pixel create 4 --type-id 4 --code 'https://network.example/pb?click=[[subid]]&payout=[[payout]]'\n  p202 ppc-account pixel create 4 --type-id 1 --code 'https://ads.example/px.gif?c=[[subid]]'",
      "runnable": true,
      "flags": [
        {
          "name": "code",
          "type": "string",
          "default": "",
          "usage": "The pixel's URL (several separated by spaces), or the markup for Raw",
          "required": false
        },
        {
          "name": "correction-url",
          "type": "string",
          "default": "",
          "usage": "Postback pixels only: where corrections go, one URL per code URL in the same order",
          "required": false
        },
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        },
        {
          "name": "type-id",
          "type": "string",
          "default": "",
          "usage": "Pixel type: 1 Image, 2 Iframe, 3 Javascript, 4 Postback (server to server), 5 Raw, 6 Bot202 Facebook Pixel Assistant: 1, 2, 3, 4, 5, 6",
          "allowed_values": [
            "1",
            "2",
            "3",
            "4",
            "5",
            "6"
          ],
          "required": false
        }
      ]
    },
    {
      "path": "p202 ppc-account pixel delete",
      "use": "delete <ppc_account_id> <pixel_id>",
      "short": "Remove a pixel from a traffic source account (with its correction URL)",
      "example": "p202 ppc-account pixel delete 4 9 --dry-run\n  p202 ppc-account pixel delete 4 9 --force",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated pixel IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ppc-account pixel list",
      "use": "list <ppc_account_id>",
      "short": "List a traffic source account's pixels",
      "example": "p202 ppc-account pixel list 4",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 ppc-account pixel update",
      "use": "update <ppc_account_id> <pixel_id>",
      "short": "Change a traffic source account's pixel",
      "example": "p202 ppc-account pixel update 4 9 --correction-url 'https://network.example/fix?tx=[[transactionid]]'\n  p202 ppc-account pixel update 4 9 --correction-url ''",
      "runnable": true,
      "flags": [
        {
          "name": "code",
          "type": "string",
          "default": "",
          "usage": "The pixel's URL (several separated by spaces), or the markup for Raw",
          "required": false
        },
        {
          "name": "correction-url",
          "type": "string",
          "default": "",
          "usage": "Postback pixels only: where corrections go, one URL per code URL in the same order",
          "required": false
        },
        {
          "name": "type-id",
          "type": "string",
          "default": "",
          "usage": "Pixel type: 1 Image, 2 Iframe, 3 Javascript, 4 Postback (server to server), 5 Raw, 6 Bot202 Facebook Pixel Assistant: 1, 2, 3, 4, 5, 6",
          "allowed_values": [
            "1",
            "2",
            "3",
            "4",
            "5",
            "6"
          ],
          "required": false
        }
      ]
    },
    {
      "path": "p202 ppc-account update",
      "use": "update <id>",
      "short": "Update a ppc-account",
      "example": "p202 ppc-account update <id from p202 ppc-account list> --ppc-account-name <new value> --json\n  (only the flags given are sent; the rest of the ppc-account is unchanged)",
      "runnable": true,
      "flags": [
        {
          "name": "ppc-account-default",
          "type": "string",
          "default": "",
          "usage": "Set as default account (1) or not (0): 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "ppc-account-name",
          "type": "string",
          "default": "",
          "usage": "Account name",
          "required": false
        },
        {
          "name": "ppc-network-id",
          "type": "string",
          "default": "",
          "usage": "PPC network ID (from `p202 ppc-network list`)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ppc-network",
      "use": "ppc-network",
      "aliases": [
        "traffic-network"
      ],
      "short": "Manage traffic source networks (PPC networks)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 ppc-network create",
      "use": "create",
      "short": "Create a new ppc-network",
      "example": "p202 ppc-network create --ppc-network-name <network_name> --json",
      "runnable": true,
      "flags": [
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        },
        {
          "name": "ppc-network-name",
          "type": "string",
          "default": "",
          "usage": "Network name (required)",
          "required": true
        }
      ]
    },
    {
      "path": "p202 ppc-network delete",
      "use": "delete <id>",
      "short": "Delete a ppc-network",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated ppc-network IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ppc-network get",
      "use": "get <id>",
      "short": "Get a ppc-network by ID",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 ppc-network list",
      "use": "list",
      "short": "List traffic source networks (PPC networks)",
      "runnable": true,
      "flags": [
        {
          "name": "all",
          "type": "bool",
          "default": "false",
          "usage": "Fetch all rows across pages",
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "page",
          "type": "string",
          "default": "",
          "usage": "Page number",
          "required": false
        },
        {
          "name": "resolve-names",
          "type": "bool",
          "default": "false",
          "usage": "Resolve foreign key IDs to names",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 ppc-network list",
          "ui_pages": [
            "Setup › Traffic Sources"
          ],
          "phrases": [
            "traffic sources",
            "ad networks"
          ]
        }
      ]
    },
    {
      "path": "p202 ppc-network update",
      "use": "update <id>",
      "short": "Update a ppc-network",
      "example": "p202 ppc-network update <id from p202 ppc-network list> --ppc-network-name <new value> --json\n  (only the flags given are sent; the rest of the ppc-network is unchanged)",
      "runnable": true,
      "flags": [
        {
          "name": "ppc-network-name",
          "type": "string",
          "default": "",
          "usage": "Network name",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ppc-network variable",
      "use": "variable",
      "aliases": [
        "variables",
        "var"
      ],
      "short": "Manage a traffic source's custom variables (the extra parameters its tracking links carry)",
      "long": "A traffic source's custom variables are the extra parameters its tracking links\ncarry, each with the placeholder the traffic source fills in: parameter=placeholder,\ne.g. adid={ad_id}. `p202 tracker get-url` writes the live ones into every link of the\nsource's accounts. A variable whose parameter is a built-in token (c1-c4, utm_*,\nt202kw, t202ref, t202b) sets that token's default instead.\n\nSetup > Traffic Sources > variables edits the same list. Needs a role with\nremove_traffic_source and access_to_setup_section (Super user or Admin; the\npage shows the variables dialog only to them) and a key with ppc-networks scope.",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 ppc-network variable create",
      "use": "create <ppc_network_id>",
      "short": "Add a custom variable to a traffic source",
      "example": "p202 ppc-network variable create 3 --name 'Ad id' --parameter adid --placeholder '{ad_id}'",
      "runnable": true,
      "flags": [
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        },
        {
          "name": "name",
          "type": "string",
          "default": "",
          "usage": "The variable's name in reports",
          "required": false
        },
        {
          "name": "parameter",
          "type": "string",
          "default": "",
          "usage": "The link's parameter, e.g. adid (no spaces, &, #, ?, =)",
          "required": false
        },
        {
          "name": "placeholder",
          "type": "string",
          "default": "",
          "usage": "What the traffic source fills in, e.g. {ad_id} (no spaces, &, #, ?)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ppc-network variable delete",
      "use": "delete <ppc_network_id> <variable_id>",
      "short": "Remove a traffic source's custom variable (new links stop carrying it)",
      "long": "Retires the variable, as the Setup dialog does: new tracking links stop carrying it,\nand clicks already recorded with it keep their values.",
      "example": "p202 ppc-network variable delete 3 7 --dry-run\n  p202 ppc-network variable delete 3 7 --force",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated variable IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 ppc-network variable list",
      "use": "list <ppc_network_id>",
      "short": "List a traffic source's custom variables",
      "example": "p202 ppc-network variable list 3",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 ppc-network variable update",
      "use": "update <ppc_network_id> <variable_id>",
      "short": "Change a traffic source's custom variable",
      "example": "p202 ppc-network variable update 3 7 --placeholder '{{ad.id}}'",
      "runnable": true,
      "flags": [
        {
          "name": "name",
          "type": "string",
          "default": "",
          "usage": "The variable's name in reports",
          "required": false
        },
        {
          "name": "parameter",
          "type": "string",
          "default": "",
          "usage": "The link's parameter, e.g. adid (no spaces, &, #, ?, =)",
          "required": false
        },
        {
          "name": "placeholder",
          "type": "string",
          "default": "",
          "usage": "What the traffic source fills in, e.g. {ad_id} (no spaces, &, #, ?)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 re-sync",
      "use": "re-sync",
      "short": "Run incremental sync using stored sync manifest",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Show sync actions without writing",
          "required": false
        },
        {
          "name": "force-update",
          "type": "bool",
          "default": "false",
          "usage": "Update mismatched target records",
          "required": false
        },
        {
          "name": "from",
          "type": "string",
          "default": "",
          "usage": "Source profile name (alias: --source)",
          "required": false
        },
        {
          "name": "skip-errors",
          "type": "bool",
          "default": "false",
          "usage": "Continue processing after record-level failures; exits 5 when any record failed, and a 401 or 403 still stops it",
          "required": false
        },
        {
          "name": "source",
          "type": "string",
          "default": "",
          "usage": "Source profile name (alias of --from)",
          "required": false
        },
        {
          "name": "target",
          "type": "string",
          "default": "",
          "usage": "Target profile name (alias of --to)",
          "required": false
        },
        {
          "name": "to",
          "type": "string",
          "default": "",
          "usage": "Target profile name (alias: --target)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 report",
      "use": "report",
      "short": "Generate performance reports — summary, breakdown by dimension, time series, and day/week parting",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 report breakdown",
      "use": "breakdown",
      "short": "Get stats broken down by a dimension (campaign, traffic source, country, landing page, etc.)",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by INTERNAL campaign id (from `campaign list`), not the public id in tracking URLs",
          "required": false
        },
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by affiliate network ID",
          "required": false
        },
        {
          "name": "breakdown",
          "shorthand": "b",
          "type": "string",
          "default": "",
          "usage": "Dimension (rows are one per stored value; clicks without one, e.g. no referer, are in `report summary` only): campaign, aff_network, ppc_account, ppc_network, landing_page, keyword, country, city, region, browser, platform, device, isp, text_ad, ip, referer, referer_url, device_type, c1, c2, c3, c4, utm_source, utm_medium, utm_campaign, utm_term, utm_content, rotator, rotator_rule (aliases: geo=country, lp=landing_page, network=aff_network, offer=campaign, referrer=referer, referrer_url=referer_url, rule=rotator_rule, source=ppc_account)",
          "allowed_values": [
            "campaign",
            "aff_network",
            "ppc_account",
            "ppc_network",
            "landing_page",
            "keyword",
            "country",
            "city",
            "region",
            "browser",
            "platform",
            "device",
            "isp",
            "text_ad",
            "ip",
            "referer",
            "referer_url",
            "device_type",
            "c1",
            "c2",
            "c3",
            "c4",
            "utm_source",
            "utm_medium",
            "utm_campaign",
            "utm_term",
            "utm_content",
            "rotator",
            "rotator_rule"
          ],
          "value_aliases": {
            "geo": "country",
            "lp": "landing_page",
            "network": "aff_network",
            "offer": "campaign",
            "referrer": "referer",
            "referrer_url": "referer_url",
            "rule": "rotator_rule",
            "source": "ppc_account"
          },
          "required": false
        },
        {
          "name": "browser-id",
          "type": "string",
          "default": "",
          "usage": "Filter by browser ID (the id of a `--breakdown browser` row)",
          "required": false
        },
        {
          "name": "country-id",
          "type": "string",
          "default": "",
          "usage": "Filter by country ID",
          "required": false
        },
        {
          "name": "device-type",
          "type": "string",
          "default": "",
          "usage": "Filter by device type ID: 1 Desktop, 2 Mobile, 3 Tablet, 4 Bot (the ids of `--breakdown device_type` rows)",
          "required": false
        },
        {
          "name": "group-by",
          "type": "string",
          "default": "",
          "usage": "Alias for --breakdown (matches `analytics --group-by`): campaign, aff_network, ppc_account, ppc_network, landing_page, keyword, country, city, region, browser, platform, device, isp, text_ad, ip, referer, referer_url, device_type, c1, c2, c3, c4, utm_source, utm_medium, utm_campaign, utm_term, utm_content, rotator, rotator_rule (aliases: geo=country, lp=landing_page, network=aff_network, offer=campaign, referrer=referer, referrer_url=referer_url, rule=rotator_rule, source=ppc_account)",
          "allowed_values": [
            "campaign",
            "aff_network",
            "ppc_account",
            "ppc_network",
            "landing_page",
            "keyword",
            "country",
            "city",
            "region",
            "browser",
            "platform",
            "device",
            "isp",
            "text_ad",
            "ip",
            "referer",
            "referer_url",
            "device_type",
            "c1",
            "c2",
            "c3",
            "c4",
            "utm_source",
            "utm_medium",
            "utm_campaign",
            "utm_term",
            "utm_content",
            "rotator",
            "rotator_rule"
          ],
          "value_aliases": {
            "geo": "country",
            "lp": "landing_page",
            "network": "aff_network",
            "offer": "campaign",
            "referrer": "referer",
            "referrer_url": "referer_url",
            "rule": "rotator_rule",
            "source": "ppc_account"
          },
          "required": false
        },
        {
          "name": "having",
          "type": "string",
          "default": "",
          "usage": "Post-filter rows: FIELD OP NUMBER, FIELD a metric column or its alias, OP one of >= <= != = > < (e.g. 'total_leads=0', 'roi<0')",
          "required": false
        },
        {
          "name": "ip",
          "type": "string",
          "default": "",
          "usage": "Only clicks from this one IP address, IPv4 or IPv6",
          "required": false
        },
        {
          "name": "isp-id",
          "type": "string",
          "default": "",
          "usage": "Filter by ISP/carrier ID (the id of a `--breakdown isp` row)",
          "required": false
        },
        {
          "name": "keyword",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose keyword contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Filter by landing page ID",
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "method-of-promotion",
          "type": "string",
          "default": "",
          "usage": "Only direct-link clicks or only landing-page clicks: directlink, landingpage",
          "allowed_values": [
            "directlink",
            "landingpage"
          ],
          "required": false
        },
        {
          "name": "min-clicks",
          "type": "float64",
          "default": "0",
          "usage": "Only rows with at least N clicks",
          "required": false
        },
        {
          "name": "min-cost",
          "type": "float64",
          "default": "0",
          "usage": "Only rows with at least $N cost",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "period",
          "shorthand": "p",
          "type": "string",
          "default": "",
          "usage": "Period: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "platform-id",
          "type": "string",
          "default": "",
          "usage": "Filter by platform (OS) ID (the id of a `--breakdown platform` row)",
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC account ID",
          "required": false
        },
        {
          "name": "ppc-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC network ID, or none for the clicks with no traffic source",
          "required": false
        },
        {
          "name": "referer",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose referring URL contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "region-id",
          "type": "string",
          "default": "",
          "usage": "Filter by region ID (the id of a `--breakdown region` row)",
          "required": false
        },
        {
          "name": "show",
          "type": "string",
          "default": "",
          "usage": "Which clicks count (default all): all, real, filtered, filtered_bot, leads; real = not filtered, filtered_bot = filtered as bots, leads = converted",
          "allowed_values": [
            "all",
            "real",
            "filtered",
            "filtered_bot",
            "leads"
          ],
          "required": false
        },
        {
          "name": "sort",
          "shorthand": "s",
          "type": "string",
          "default": "",
          "usage": "Sort by: total_clicks, total_click_throughs, total_leads, total_income, total_cost, total_net, epc, avg_cpc, conv_rate, roi, cpa (aliases: clicks=total_clicks, conversions=total_leads, cost=total_cost, income=total_income, leads=total_leads, net=total_net, profit=total_net, revenue=total_income)",
          "allowed_values": [
            "total_clicks",
            "total_click_throughs",
            "total_leads",
            "total_income",
            "total_cost",
            "total_net",
            "epc",
            "avg_cpc",
            "conv_rate",
            "roi",
            "cpa"
          ],
          "value_aliases": {
            "clicks": "total_clicks",
            "conversions": "total_leads",
            "cost": "total_cost",
            "income": "total_income",
            "leads": "total_leads",
            "net": "total_net",
            "profit": "total_net",
            "revenue": "total_income"
          },
          "required": false
        },
        {
          "name": "sort-dir",
          "type": "string",
          "default": "",
          "usage": "Sort direction: ASC, DESC",
          "allowed_values": [
            "ASC",
            "DESC"
          ],
          "required": false
        },
        {
          "name": "text-ad-id",
          "type": "string",
          "default": "",
          "usage": "Filter by text ad ID",
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "End, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
          "required": false
        },
        {
          "name": "zero-leads",
          "type": "bool",
          "default": "false",
          "usage": "Only rows with cost > 0 and zero conversions (pure waste)",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 report breakdown --breakdown campaign",
          "ui_pages": [
            "Overview › Campaign Overview"
          ],
          "phrases": [
            "campaign performance",
            "stats per campaign"
          ]
        },
        {
          "run": "p202 report breakdown --breakdown keyword",
          "ui_pages": [
            "Analyze › Keywords"
          ]
        },
        {
          "run": "p202 report breakdown --breakdown text_ad",
          "ui_pages": [
            "Analyze › Text Ads"
          ]
        },
        {
          "run": "p202 report breakdown --breakdown referer",
          "ui_pages": [
            "Analyze › Referers"
          ]
        },
        {
          "run": "p202 report breakdown --breakdown ip",
          "ui_pages": [
            "Analyze › IPs"
          ]
        },
        {
          "run": "p202 report breakdown --breakdown country",
          "ui_pages": [
            "Analyze › Countries"
          ]
        },
        {
          "run": "p202 report breakdown --breakdown region",
          "ui_pages": [
            "Analyze › Regions"
          ]
        },
        {
          "run": "p202 report breakdown --breakdown city",
          "ui_pages": [
            "Analyze › Cities"
          ]
        },
        {
          "run": "p202 report breakdown --breakdown isp",
          "ui_pages": [
            "Analyze › ISP/Carrier"
          ]
        },
        {
          "run": "p202 report breakdown --breakdown landing_page",
          "ui_pages": [
            "Analyze › Landing Pages"
          ]
        },
        {
          "run": "p202 report breakdown --breakdown device",
          "ui_pages": [
            "Analyze › Devices"
          ]
        },
        {
          "run": "p202 report breakdown --breakdown browser",
          "ui_pages": [
            "Analyze › Browsers"
          ]
        },
        {
          "run": "p202 report breakdown --breakdown platform",
          "ui_pages": [
            "Analyze › Platforms"
          ]
        },
        {
          "run": "p202 report breakdown --breakdown c1",
          "ui_pages": [
            "Analyze › Custom Variables"
          ],
          "phrases": [
            "c1 c2 c3 c4",
            "custom variable breakdown"
          ]
        }
      ]
    },
    {
      "path": "p202 report breakeven",
      "use": "breakeven",
      "short": "Break-even CPC per row: max biddable click price (payout × conversion rate)",
      "long": "Computes the maximum profitable cost-per-click for each breakdown row.\nbreakeven_cpc = campaign payout × (conversions / clicks); margin = breakeven_cpc − avg_cpc.\nRequires --aff-campaign-id (the INTERNAL id from `campaign list`) to read the payout.",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by INTERNAL campaign id (from `campaign list`), not the public id in tracking URLs",
          "required": false
        },
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by affiliate network ID",
          "required": false
        },
        {
          "name": "breakdown",
          "shorthand": "b",
          "type": "string",
          "default": "keyword",
          "usage": "Dimension: campaign, aff_network, ppc_account, ppc_network, landing_page, keyword, country, city, region, browser, platform, device, isp, text_ad, ip, referer, referer_url, device_type, c1, c2, c3, c4, utm_source, utm_medium, utm_campaign, utm_term, utm_content, rotator, rotator_rule (aliases: geo=country, lp=landing_page, network=aff_network, offer=campaign, referrer=referer, referrer_url=referer_url, rule=rotator_rule, source=ppc_account)",
          "allowed_values": [
            "campaign",
            "aff_network",
            "ppc_account",
            "ppc_network",
            "landing_page",
            "keyword",
            "country",
            "city",
            "region",
            "browser",
            "platform",
            "device",
            "isp",
            "text_ad",
            "ip",
            "referer",
            "referer_url",
            "device_type",
            "c1",
            "c2",
            "c3",
            "c4",
            "utm_source",
            "utm_medium",
            "utm_campaign",
            "utm_term",
            "utm_content",
            "rotator",
            "rotator_rule"
          ],
          "value_aliases": {
            "geo": "country",
            "lp": "landing_page",
            "network": "aff_network",
            "offer": "campaign",
            "referrer": "referer",
            "referrer_url": "referer_url",
            "rule": "rotator_rule",
            "source": "ppc_account"
          },
          "required": false
        },
        {
          "name": "browser-id",
          "type": "string",
          "default": "",
          "usage": "Filter by browser ID (the id of a `--breakdown browser` row)",
          "required": false
        },
        {
          "name": "country-id",
          "type": "string",
          "default": "",
          "usage": "Filter by country ID",
          "required": false
        },
        {
          "name": "device-type",
          "type": "string",
          "default": "",
          "usage": "Filter by device type ID: 1 Desktop, 2 Mobile, 3 Tablet, 4 Bot (the ids of `--breakdown device_type` rows)",
          "required": false
        },
        {
          "name": "ip",
          "type": "string",
          "default": "",
          "usage": "Only clicks from this one IP address, IPv4 or IPv6",
          "required": false
        },
        {
          "name": "isp-id",
          "type": "string",
          "default": "",
          "usage": "Filter by ISP/carrier ID (the id of a `--breakdown isp` row)",
          "required": false
        },
        {
          "name": "keyword",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose keyword contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Filter by landing page ID",
          "required": false
        },
        {
          "name": "max-cpc",
          "type": "float64",
          "default": "0",
          "usage": "Override the payout-derived break-even CPC target",
          "required": false
        },
        {
          "name": "method-of-promotion",
          "type": "string",
          "default": "",
          "usage": "Only direct-link clicks or only landing-page clicks: directlink, landingpage",
          "allowed_values": [
            "directlink",
            "landingpage"
          ],
          "required": false
        },
        {
          "name": "period",
          "shorthand": "p",
          "type": "string",
          "default": "",
          "usage": "Period: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "platform-id",
          "type": "string",
          "default": "",
          "usage": "Filter by platform (OS) ID (the id of a `--breakdown platform` row)",
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC account ID",
          "required": false
        },
        {
          "name": "ppc-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC network ID, or none for the clicks with no traffic source",
          "required": false
        },
        {
          "name": "referer",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose referring URL contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "region-id",
          "type": "string",
          "default": "",
          "usage": "Filter by region ID (the id of a `--breakdown region` row)",
          "required": false
        },
        {
          "name": "show",
          "type": "string",
          "default": "",
          "usage": "Which clicks count (default all): all, real, filtered, filtered_bot, leads; real = not filtered, filtered_bot = filtered as bots, leads = converted",
          "allowed_values": [
            "all",
            "real",
            "filtered",
            "filtered_bot",
            "leads"
          ],
          "required": false
        },
        {
          "name": "text-ad-id",
          "type": "string",
          "default": "",
          "usage": "Filter by text ad ID",
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "End, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
          "required": false
        }
      ]
    },
    {
      "path": "p202 report crosstab",
      "use": "crosstab",
      "short": "Two-dimension breakdown (e.g. traffic source × country) for one metric",
      "long": "Pivots one metric across two dimensions by fanning out a breakdown per row.\nExample: report crosstab --rows ppc_account --cols country --metric profit --aff-campaign-id 90008",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by INTERNAL campaign id (from `campaign list`), not the public id in tracking URLs",
          "required": false
        },
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by affiliate network ID",
          "required": false
        },
        {
          "name": "browser-id",
          "type": "string",
          "default": "",
          "usage": "Filter by browser ID (the id of a `--breakdown browser` row)",
          "required": false
        },
        {
          "name": "cols",
          "type": "string",
          "default": "",
          "usage": "Column dimension: campaign, aff_network, ppc_account, ppc_network, landing_page, keyword, country, city, region, browser, platform, device, isp, text_ad, ip, referer, referer_url, device_type, c1, c2, c3, c4, utm_source, utm_medium, utm_campaign, utm_term, utm_content, rotator, rotator_rule (aliases: geo=country, lp=landing_page, network=aff_network, offer=campaign, referrer=referer, referrer_url=referer_url, rule=rotator_rule, source=ppc_account)",
          "allowed_values": [
            "campaign",
            "aff_network",
            "ppc_account",
            "ppc_network",
            "landing_page",
            "keyword",
            "country",
            "city",
            "region",
            "browser",
            "platform",
            "device",
            "isp",
            "text_ad",
            "ip",
            "referer",
            "referer_url",
            "device_type",
            "c1",
            "c2",
            "c3",
            "c4",
            "utm_source",
            "utm_medium",
            "utm_campaign",
            "utm_term",
            "utm_content",
            "rotator",
            "rotator_rule"
          ],
          "value_aliases": {
            "geo": "country",
            "lp": "landing_page",
            "network": "aff_network",
            "offer": "campaign",
            "referrer": "referer",
            "referrer_url": "referer_url",
            "rule": "rotator_rule",
            "source": "ppc_account"
          },
          "required": false
        },
        {
          "name": "country-id",
          "type": "string",
          "default": "",
          "usage": "Filter by country ID",
          "required": false
        },
        {
          "name": "device-type",
          "type": "string",
          "default": "",
          "usage": "Filter by device type ID: 1 Desktop, 2 Mobile, 3 Tablet, 4 Bot (the ids of `--breakdown device_type` rows)",
          "required": false
        },
        {
          "name": "ip",
          "type": "string",
          "default": "",
          "usage": "Only clicks from this one IP address, IPv4 or IPv6",
          "required": false
        },
        {
          "name": "isp-id",
          "type": "string",
          "default": "",
          "usage": "Filter by ISP/carrier ID (the id of a `--breakdown isp` row)",
          "required": false
        },
        {
          "name": "keyword",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose keyword contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Filter by landing page ID",
          "required": false
        },
        {
          "name": "limit-rows",
          "type": "int",
          "default": "20",
          "usage": "Cap the number of rows fanned out",
          "required": false
        },
        {
          "name": "method-of-promotion",
          "type": "string",
          "default": "",
          "usage": "Only direct-link clicks or only landing-page clicks: directlink, landingpage",
          "allowed_values": [
            "directlink",
            "landingpage"
          ],
          "required": false
        },
        {
          "name": "metric",
          "type": "string",
          "default": "total_net",
          "usage": "Metric to pivot: total_clicks, total_click_throughs, total_leads, total_income, total_cost, total_net, epc, avg_cpc, conv_rate, roi, cpa (aliases: clicks=total_clicks, conversions=total_leads, cost=total_cost, income=total_income, leads=total_leads, net=total_net, profit=total_net, revenue=total_income)",
          "allowed_values": [
            "total_clicks",
            "total_click_throughs",
            "total_leads",
            "total_income",
            "total_cost",
            "total_net",
            "epc",
            "avg_cpc",
            "conv_rate",
            "roi",
            "cpa"
          ],
          "value_aliases": {
            "clicks": "total_clicks",
            "conversions": "total_leads",
            "cost": "total_cost",
            "income": "total_income",
            "leads": "total_leads",
            "net": "total_net",
            "profit": "total_net",
            "revenue": "total_income"
          },
          "required": false
        },
        {
          "name": "period",
          "shorthand": "p",
          "type": "string",
          "default": "",
          "usage": "Period: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "platform-id",
          "type": "string",
          "default": "",
          "usage": "Filter by platform (OS) ID (the id of a `--breakdown platform` row)",
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC account ID",
          "required": false
        },
        {
          "name": "ppc-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC network ID, or none for the clicks with no traffic source",
          "required": false
        },
        {
          "name": "referer",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose referring URL contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "region-id",
          "type": "string",
          "default": "",
          "usage": "Filter by region ID (the id of a `--breakdown region` row)",
          "required": false
        },
        {
          "name": "rows",
          "type": "string",
          "default": "",
          "usage": "Row dimension (one with an id filter): campaign, aff_network, ppc_account, ppc_network, landing_page, country, region, browser, platform, isp, text_ad, device_type (aliases: geo=country, lp=landing_page, network=aff_network, offer=campaign, source=ppc_account)",
          "allowed_values": [
            "campaign",
            "aff_network",
            "ppc_account",
            "ppc_network",
            "landing_page",
            "country",
            "region",
            "browser",
            "platform",
            "isp",
            "text_ad",
            "device_type"
          ],
          "value_aliases": {
            "geo": "country",
            "lp": "landing_page",
            "network": "aff_network",
            "offer": "campaign",
            "source": "ppc_account"
          },
          "required": false
        },
        {
          "name": "show",
          "type": "string",
          "default": "",
          "usage": "Which clicks count (default all): all, real, filtered, filtered_bot, leads; real = not filtered, filtered_bot = filtered as bots, leads = converted",
          "allowed_values": [
            "all",
            "real",
            "filtered",
            "filtered_bot",
            "leads"
          ],
          "required": false
        },
        {
          "name": "text-ad-id",
          "type": "string",
          "default": "",
          "usage": "Filter by text ad ID",
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "End, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
          "required": false
        }
      ]
    },
    {
      "path": "p202 report daypart",
      "use": "daypart",
      "short": "Get stats grouped by hour of day (0-23) to find best-performing hours",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by INTERNAL campaign id (from `campaign list`), not the public id in tracking URLs",
          "required": false
        },
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by affiliate network ID",
          "required": false
        },
        {
          "name": "browser-id",
          "type": "string",
          "default": "",
          "usage": "Filter by browser ID (the id of a `--breakdown browser` row)",
          "required": false
        },
        {
          "name": "country-id",
          "type": "string",
          "default": "",
          "usage": "Filter by country ID",
          "required": false
        },
        {
          "name": "device-type",
          "type": "string",
          "default": "",
          "usage": "Filter by device type ID: 1 Desktop, 2 Mobile, 3 Tablet, 4 Bot (the ids of `--breakdown device_type` rows)",
          "required": false
        },
        {
          "name": "ip",
          "type": "string",
          "default": "",
          "usage": "Only clicks from this one IP address, IPv4 or IPv6",
          "required": false
        },
        {
          "name": "isp-id",
          "type": "string",
          "default": "",
          "usage": "Filter by ISP/carrier ID (the id of a `--breakdown isp` row)",
          "required": false
        },
        {
          "name": "keyword",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose keyword contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Filter by landing page ID",
          "required": false
        },
        {
          "name": "method-of-promotion",
          "type": "string",
          "default": "",
          "usage": "Only direct-link clicks or only landing-page clicks: directlink, landingpage",
          "allowed_values": [
            "directlink",
            "landingpage"
          ],
          "required": false
        },
        {
          "name": "period",
          "shorthand": "p",
          "type": "string",
          "default": "",
          "usage": "Period: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "platform-id",
          "type": "string",
          "default": "",
          "usage": "Filter by platform (OS) ID (the id of a `--breakdown platform` row)",
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC account ID",
          "required": false
        },
        {
          "name": "ppc-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC network ID, or none for the clicks with no traffic source",
          "required": false
        },
        {
          "name": "referer",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose referring URL contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "region-id",
          "type": "string",
          "default": "",
          "usage": "Filter by region ID (the id of a `--breakdown region` row)",
          "required": false
        },
        {
          "name": "show",
          "type": "string",
          "default": "",
          "usage": "Which clicks count (default all): all, real, filtered, filtered_bot, leads; real = not filtered, filtered_bot = filtered as bots, leads = converted",
          "allowed_values": [
            "all",
            "real",
            "filtered",
            "filtered_bot",
            "leads"
          ],
          "required": false
        },
        {
          "name": "sort",
          "shorthand": "s",
          "type": "string",
          "default": "",
          "usage": "Sort by: hour_of_day, total_clicks, total_click_throughs, total_leads, total_income, total_cost, total_net, epc, avg_cpc, conv_rate, roi, cpa (aliases: clicks=total_clicks, conversions=total_leads, cost=total_cost, income=total_income, leads=total_leads, net=total_net, profit=total_net, revenue=total_income)",
          "allowed_values": [
            "hour_of_day",
            "total_clicks",
            "total_click_throughs",
            "total_leads",
            "total_income",
            "total_cost",
            "total_net",
            "epc",
            "avg_cpc",
            "conv_rate",
            "roi",
            "cpa"
          ],
          "value_aliases": {
            "clicks": "total_clicks",
            "conversions": "total_leads",
            "cost": "total_cost",
            "income": "total_income",
            "leads": "total_leads",
            "net": "total_net",
            "profit": "total_net",
            "revenue": "total_income"
          },
          "required": false
        },
        {
          "name": "sort-dir",
          "type": "string",
          "default": "",
          "usage": "Sort direction (also --sort-dir): ASC, DESC",
          "allowed_values": [
            "ASC",
            "DESC"
          ],
          "required": false
        },
        {
          "name": "text-ad-id",
          "type": "string",
          "default": "",
          "usage": "Filter by text ad ID",
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "End, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 report daypart",
          "ui_pages": [
            "Overview › Day Parting"
          ],
          "phrases": [
            "dayparting",
            "time of day"
          ]
        }
      ]
    },
    {
      "path": "p202 report groups",
      "use": "groups",
      "short": "Traffic grouped by up to four dimensions, nested, each group with its totals (Group Overview)",
      "long": "The Overview's Group Overview: traffic grouped by up to four dimensions, one inside\nthe other, every group with its clicks, leads, income, cost, net and ratios. A group\nis the sum of its children: the clicks a level has no value for (no keyword, no\nlanding page) are its `[no keyword]` row. Takes every report filter and period.\n\n--json answers the tree as the server serves it (each group's `children`); the table,\nCSV and --ndjson give one row per group, marked by level (› per level), then a Total row.\n\n  p202 report groups --by ppc_network,campaign,keyword --period last7\n  p202 report groups --by campaign,device_type --show real --sort clicks --json",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by INTERNAL campaign id (from `campaign list`), not the public id in tracking URLs",
          "required": false
        },
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by affiliate network ID",
          "required": false
        },
        {
          "name": "browser-id",
          "type": "string",
          "default": "",
          "usage": "Filter by browser ID (the id of a `--breakdown browser` row)",
          "required": false
        },
        {
          "name": "by",
          "type": "string",
          "default": "",
          "usage": "Up to 4 dimensions, outermost first (e.g. ppc_network,campaign,keyword): campaign, aff_network, ppc_account, ppc_network, landing_page, keyword, country, city, region, browser, platform, device, isp, text_ad, ip, referer, referer_url, device_type, c1, c2, c3, c4, utm_source, utm_medium, utm_campaign, utm_term, utm_content, rotator, rotator_rule (aliases: geo=country, lp=landing_page, network=aff_network, offer=campaign, referrer=referer, referrer_url=referer_url, rule=rotator_rule, source=ppc_account); comma-separated for several",
          "allowed_values": [
            "campaign",
            "aff_network",
            "ppc_account",
            "ppc_network",
            "landing_page",
            "keyword",
            "country",
            "city",
            "region",
            "browser",
            "platform",
            "device",
            "isp",
            "text_ad",
            "ip",
            "referer",
            "referer_url",
            "device_type",
            "c1",
            "c2",
            "c3",
            "c4",
            "utm_source",
            "utm_medium",
            "utm_campaign",
            "utm_term",
            "utm_content",
            "rotator",
            "rotator_rule"
          ],
          "value_aliases": {
            "geo": "country",
            "lp": "landing_page",
            "network": "aff_network",
            "offer": "campaign",
            "referrer": "referer",
            "referrer_url": "referer_url",
            "rule": "rotator_rule",
            "source": "ppc_account"
          },
          "value_list": true,
          "required": false
        },
        {
          "name": "country-id",
          "type": "string",
          "default": "",
          "usage": "Filter by country ID",
          "required": false
        },
        {
          "name": "device-type",
          "type": "string",
          "default": "",
          "usage": "Filter by device type ID: 1 Desktop, 2 Mobile, 3 Tablet, 4 Bot (the ids of `--breakdown device_type` rows)",
          "required": false
        },
        {
          "name": "ip",
          "type": "string",
          "default": "",
          "usage": "Only clicks from this one IP address, IPv4 or IPv6",
          "required": false
        },
        {
          "name": "isp-id",
          "type": "string",
          "default": "",
          "usage": "Filter by ISP/carrier ID (the id of a `--breakdown isp` row)",
          "required": false
        },
        {
          "name": "keyword",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose keyword contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Filter by landing page ID",
          "required": false
        },
        {
          "name": "method-of-promotion",
          "type": "string",
          "default": "",
          "usage": "Only direct-link clicks or only landing-page clicks: directlink, landingpage",
          "allowed_values": [
            "directlink",
            "landingpage"
          ],
          "required": false
        },
        {
          "name": "period",
          "shorthand": "p",
          "type": "string",
          "default": "",
          "usage": "Period: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "platform-id",
          "type": "string",
          "default": "",
          "usage": "Filter by platform (OS) ID (the id of a `--breakdown platform` row)",
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC account ID",
          "required": false
        },
        {
          "name": "ppc-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC network ID, or none for the clicks with no traffic source",
          "required": false
        },
        {
          "name": "referer",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose referring URL contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "region-id",
          "type": "string",
          "default": "",
          "usage": "Filter by region ID (the id of a `--breakdown region` row)",
          "required": false
        },
        {
          "name": "show",
          "type": "string",
          "default": "",
          "usage": "Which clicks count (default all): all, real, filtered, filtered_bot, leads; real = not filtered, filtered_bot = filtered as bots, leads = converted",
          "allowed_values": [
            "all",
            "real",
            "filtered",
            "filtered_bot",
            "leads"
          ],
          "required": false
        },
        {
          "name": "sort",
          "type": "string",
          "default": "",
          "usage": "Order each group's rows by name (default) or a metric: name, total_clicks, total_click_throughs, total_leads, total_income, total_cost, total_net, epc, avg_cpc, conv_rate, roi, cpa (aliases: clicks=total_clicks, conversions=total_leads, cost=total_cost, income=total_income, leads=total_leads, net=total_net, profit=total_net, revenue=total_income)",
          "allowed_values": [
            "name",
            "total_clicks",
            "total_click_throughs",
            "total_leads",
            "total_income",
            "total_cost",
            "total_net",
            "epc",
            "avg_cpc",
            "conv_rate",
            "roi",
            "cpa"
          ],
          "value_aliases": {
            "clicks": "total_clicks",
            "conversions": "total_leads",
            "cost": "total_cost",
            "income": "total_income",
            "leads": "total_leads",
            "net": "total_net",
            "profit": "total_net",
            "revenue": "total_income"
          },
          "required": false
        },
        {
          "name": "sort-dir",
          "type": "string",
          "default": "",
          "usage": "ASC or DESC (default ASC by name, DESC by a metric): ASC, DESC",
          "allowed_values": [
            "ASC",
            "DESC"
          ],
          "required": false
        },
        {
          "name": "text-ad-id",
          "type": "string",
          "default": "",
          "usage": "Filter by text ad ID",
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "End, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 report groups",
          "ui_pages": [
            "Overview › Group Overview"
          ],
          "phrases": [
            "nested report",
            "group by several dimensions"
          ]
        }
      ]
    },
    {
      "path": "p202 report losers",
      "use": "losers",
      "short": "Rows to CUT: over-bid keywords/geos and zero-conversion spend; rows that start sales come back as TEST",
      "long": "Rows to CUT from the classic (last-click) report: zero conversions with spend, or CPC above break-even.\nBreak-even is --max-cpc, or a payout × the row's own conversion rate: --payout (your revenue per conversion) or\nthe payout of --aff-campaign-id. Without one, only zero-conversion spend is CUT: a row that sells at a loss is\nWATCH and isn't listed. --payout doesn't filter the report, so the attribution check below still runs, and it\nvalues every sale the command reports at that payout: total_net, and the first-touch ROI below. The classic report\ncounts a converted click once however many sales it had, so the check also reads the Last touch model, whose\ncredits count each row's sales, and values the rows it reads per sale (a stderr note says when it can't).\n\nEach CUT row is then checked against the attribution report for the same dimension and range. A row that\nstarts sales comes back as TEST, with its first-touch ROI and assists: it pays for itself as a first click\n(first-touch ROI 0% or better), or it had a click in at least --min-assists sales (default 1) that another row\nclosed. Cutting it on last-click numbers would likely lose those sales, so test a cut on part of its traffic first.\n\nThe check runs for campaign, ppc_account (traffic source), landing_page, keyword and country. ROI comes from the\nfirst active First touch model (or --first-touch-model); without one, rows are checked on assists only. It needs\nan attribution:read key; when it can't run, the command still lists the classic losers and says why on stderr.\nA filter other than the breakdown itself (an entity id, --keyword, --show, --ip, ...) turns the check off: the\nattribution report is account-wide.\nOn a server that can't page the attribution report, rows past the first page are marked attribution_checked:\nfalse. --no-attribution-check turns it off.",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by INTERNAL campaign id (from `campaign list`), not the public id in tracking URLs",
          "required": false
        },
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by affiliate network ID",
          "required": false
        },
        {
          "name": "breakdown",
          "shorthand": "b",
          "type": "string",
          "default": "keyword",
          "usage": "Dimension to triage: campaign, aff_network, ppc_account, ppc_network, landing_page, keyword, country, city, region, browser, platform, device, isp, text_ad, ip, referer, referer_url, device_type, c1, c2, c3, c4, utm_source, utm_medium, utm_campaign, utm_term, utm_content, rotator, rotator_rule (aliases: geo=country, lp=landing_page, network=aff_network, offer=campaign, referrer=referer, referrer_url=referer_url, rule=rotator_rule, source=ppc_account)",
          "allowed_values": [
            "campaign",
            "aff_network",
            "ppc_account",
            "ppc_network",
            "landing_page",
            "keyword",
            "country",
            "city",
            "region",
            "browser",
            "platform",
            "device",
            "isp",
            "text_ad",
            "ip",
            "referer",
            "referer_url",
            "device_type",
            "c1",
            "c2",
            "c3",
            "c4",
            "utm_source",
            "utm_medium",
            "utm_campaign",
            "utm_term",
            "utm_content",
            "rotator",
            "rotator_rule"
          ],
          "value_aliases": {
            "geo": "country",
            "lp": "landing_page",
            "network": "aff_network",
            "offer": "campaign",
            "referrer": "referer",
            "referrer_url": "referer_url",
            "rule": "rotator_rule",
            "source": "ppc_account"
          },
          "required": false
        },
        {
          "name": "browser-id",
          "type": "string",
          "default": "",
          "usage": "Filter by browser ID (the id of a `--breakdown browser` row)",
          "required": false
        },
        {
          "name": "country-id",
          "type": "string",
          "default": "",
          "usage": "Filter by country ID",
          "required": false
        },
        {
          "name": "device-type",
          "type": "string",
          "default": "",
          "usage": "Filter by device type ID: 1 Desktop, 2 Mobile, 3 Tablet, 4 Bot (the ids of `--breakdown device_type` rows)",
          "required": false
        },
        {
          "name": "first-touch-model",
          "type": "string",
          "default": "",
          "usage": "Attribution model id for the starter check (default: the first active First touch model)",
          "required": false
        },
        {
          "name": "ip",
          "type": "string",
          "default": "",
          "usage": "Only clicks from this one IP address, IPv4 or IPv6",
          "required": false
        },
        {
          "name": "isp-id",
          "type": "string",
          "default": "",
          "usage": "Filter by ISP/carrier ID (the id of a `--breakdown isp` row)",
          "required": false
        },
        {
          "name": "keyword",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose keyword contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Filter by landing page ID",
          "required": false
        },
        {
          "name": "max-cpc",
          "type": "float64",
          "default": "0",
          "usage": "Break-even CPC target (else payout × each row's CVR, from --payout or the campaign)",
          "required": false
        },
        {
          "name": "method-of-promotion",
          "type": "string",
          "default": "",
          "usage": "Only direct-link clicks or only landing-page clicks: directlink, landingpage",
          "allowed_values": [
            "directlink",
            "landingpage"
          ],
          "required": false
        },
        {
          "name": "min-assists",
          "type": "int64",
          "default": "1",
          "usage": "A CUT row with at least this many assisted sales comes back as TEST (0 turns the assists rule off)",
          "required": false
        },
        {
          "name": "min-clicks",
          "type": "float64",
          "default": "1",
          "usage": "Ignore rows with fewer than N clicks (significance floor)",
          "required": false
        },
        {
          "name": "no-attribution-check",
          "type": "bool",
          "default": "false",
          "usage": "List classic last-click losers only, without the first-touch starter check",
          "required": false
        },
        {
          "name": "payout",
          "type": "float64",
          "default": "0",
          "usage": "Revenue per conversion, e.g. your average order value: each row's break-even CPC is this × its conversion rate, and its profit (total_net) and first-touch ROI value each sale at this. Unlike --aff-campaign-id it doesn't filter the report, so the attribution check still runs",
          "required": false
        },
        {
          "name": "period",
          "shorthand": "p",
          "type": "string",
          "default": "",
          "usage": "Period: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "platform-id",
          "type": "string",
          "default": "",
          "usage": "Filter by platform (OS) ID (the id of a `--breakdown platform` row)",
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC account ID",
          "required": false
        },
        {
          "name": "ppc-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC network ID, or none for the clicks with no traffic source",
          "required": false
        },
        {
          "name": "referer",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose referring URL contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "region-id",
          "type": "string",
          "default": "",
          "usage": "Filter by region ID (the id of a `--breakdown region` row)",
          "required": false
        },
        {
          "name": "show",
          "type": "string",
          "default": "",
          "usage": "Which clicks count (default all): all, real, filtered, filtered_bot, leads; real = not filtered, filtered_bot = filtered as bots, leads = converted",
          "allowed_values": [
            "all",
            "real",
            "filtered",
            "filtered_bot",
            "leads"
          ],
          "required": false
        },
        {
          "name": "text-ad-id",
          "type": "string",
          "default": "",
          "usage": "Filter by text ad ID",
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "End, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
          "required": false
        }
      ]
    },
    {
      "path": "p202 report summary",
      "use": "summary",
      "short": "Get aggregate totals — clicks, conversions, revenue, cost, profit, ROI for a period",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by INTERNAL campaign id (from `campaign list`), not the public id in tracking URLs",
          "required": false
        },
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by affiliate network ID",
          "required": false
        },
        {
          "name": "all-profiles",
          "type": "bool",
          "default": "false",
          "usage": "Run against all configured profiles",
          "required": false
        },
        {
          "name": "browser-id",
          "type": "string",
          "default": "",
          "usage": "Filter by browser ID (the id of a `--breakdown browser` row)",
          "required": false
        },
        {
          "name": "country-id",
          "type": "string",
          "default": "",
          "usage": "Filter by country ID",
          "required": false
        },
        {
          "name": "device-type",
          "type": "string",
          "default": "",
          "usage": "Filter by device type ID: 1 Desktop, 2 Mobile, 3 Tablet, 4 Bot (the ids of `--breakdown device_type` rows)",
          "required": false
        },
        {
          "name": "ip",
          "type": "string",
          "default": "",
          "usage": "Only clicks from this one IP address, IPv4 or IPv6",
          "required": false
        },
        {
          "name": "isp-id",
          "type": "string",
          "default": "",
          "usage": "Filter by ISP/carrier ID (the id of a `--breakdown isp` row)",
          "required": false
        },
        {
          "name": "keyword",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose keyword contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Filter by landing page ID",
          "required": false
        },
        {
          "name": "method-of-promotion",
          "type": "string",
          "default": "",
          "usage": "Only direct-link clicks or only landing-page clicks: directlink, landingpage",
          "allowed_values": [
            "directlink",
            "landingpage"
          ],
          "required": false
        },
        {
          "name": "period",
          "shorthand": "p",
          "type": "string",
          "default": "",
          "usage": "Period: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "platform-id",
          "type": "string",
          "default": "",
          "usage": "Filter by platform (OS) ID (the id of a `--breakdown platform` row)",
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC account ID",
          "required": false
        },
        {
          "name": "ppc-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC network ID, or none for the clicks with no traffic source",
          "required": false
        },
        {
          "name": "profiles",
          "type": "string",
          "default": "",
          "usage": "Comma-separated profile names",
          "required": false
        },
        {
          "name": "referer",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose referring URL contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "region-id",
          "type": "string",
          "default": "",
          "usage": "Filter by region ID (the id of a `--breakdown region` row)",
          "required": false
        },
        {
          "name": "show",
          "type": "string",
          "default": "",
          "usage": "Which clicks count (default all): all, real, filtered, filtered_bot, leads; real = not filtered, filtered_bot = filtered as bots, leads = converted",
          "allowed_values": [
            "all",
            "real",
            "filtered",
            "filtered_bot",
            "leads"
          ],
          "required": false
        },
        {
          "name": "text-ad-id",
          "type": "string",
          "default": "",
          "usage": "Filter by text ad ID",
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "End, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
          "required": false
        }
      ]
    },
    {
      "path": "p202 report timeseries",
      "use": "timeseries",
      "short": "Get stats over time — daily/hourly buckets of clicks, conversions, revenue, etc.",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by INTERNAL campaign id (from `campaign list`), not the public id in tracking URLs",
          "required": false
        },
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by affiliate network ID",
          "required": false
        },
        {
          "name": "browser-id",
          "type": "string",
          "default": "",
          "usage": "Filter by browser ID (the id of a `--breakdown browser` row)",
          "required": false
        },
        {
          "name": "country-id",
          "type": "string",
          "default": "",
          "usage": "Filter by country ID",
          "required": false
        },
        {
          "name": "device-type",
          "type": "string",
          "default": "",
          "usage": "Filter by device type ID: 1 Desktop, 2 Mobile, 3 Tablet, 4 Bot (the ids of `--breakdown device_type` rows)",
          "required": false
        },
        {
          "name": "interval",
          "shorthand": "i",
          "type": "string",
          "default": "",
          "usage": "Interval: hour, day, week, month",
          "required": false
        },
        {
          "name": "ip",
          "type": "string",
          "default": "",
          "usage": "Only clicks from this one IP address, IPv4 or IPv6",
          "required": false
        },
        {
          "name": "isp-id",
          "type": "string",
          "default": "",
          "usage": "Filter by ISP/carrier ID (the id of a `--breakdown isp` row)",
          "required": false
        },
        {
          "name": "keyword",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose keyword contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Filter by landing page ID",
          "required": false
        },
        {
          "name": "method-of-promotion",
          "type": "string",
          "default": "",
          "usage": "Only direct-link clicks or only landing-page clicks: directlink, landingpage",
          "allowed_values": [
            "directlink",
            "landingpage"
          ],
          "required": false
        },
        {
          "name": "period",
          "shorthand": "p",
          "type": "string",
          "default": "",
          "usage": "Period: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "platform-id",
          "type": "string",
          "default": "",
          "usage": "Filter by platform (OS) ID (the id of a `--breakdown platform` row)",
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC account ID",
          "required": false
        },
        {
          "name": "ppc-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC network ID, or none for the clicks with no traffic source",
          "required": false
        },
        {
          "name": "referer",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose referring URL contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "region-id",
          "type": "string",
          "default": "",
          "usage": "Filter by region ID (the id of a `--breakdown region` row)",
          "required": false
        },
        {
          "name": "show",
          "type": "string",
          "default": "",
          "usage": "Which clicks count (default all): all, real, filtered, filtered_bot, leads; real = not filtered, filtered_bot = filtered as bots, leads = converted",
          "allowed_values": [
            "all",
            "real",
            "filtered",
            "filtered_bot",
            "leads"
          ],
          "required": false
        },
        {
          "name": "text-ad-id",
          "type": "string",
          "default": "",
          "usage": "Filter by text ad ID",
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "End, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 report timeseries",
          "ui_pages": [
            "Overview › Breakdown Analysis"
          ],
          "phrases": [
            "performance over time",
            "daily stats",
            "trend"
          ]
        }
      ]
    },
    {
      "path": "p202 report weekpart",
      "use": "weekpart",
      "short": "Get stats grouped by day of week (Mon-Sun) to find best-performing days",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by INTERNAL campaign id (from `campaign list`), not the public id in tracking URLs",
          "required": false
        },
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by affiliate network ID",
          "required": false
        },
        {
          "name": "browser-id",
          "type": "string",
          "default": "",
          "usage": "Filter by browser ID (the id of a `--breakdown browser` row)",
          "required": false
        },
        {
          "name": "country-id",
          "type": "string",
          "default": "",
          "usage": "Filter by country ID",
          "required": false
        },
        {
          "name": "device-type",
          "type": "string",
          "default": "",
          "usage": "Filter by device type ID: 1 Desktop, 2 Mobile, 3 Tablet, 4 Bot (the ids of `--breakdown device_type` rows)",
          "required": false
        },
        {
          "name": "ip",
          "type": "string",
          "default": "",
          "usage": "Only clicks from this one IP address, IPv4 or IPv6",
          "required": false
        },
        {
          "name": "isp-id",
          "type": "string",
          "default": "",
          "usage": "Filter by ISP/carrier ID (the id of a `--breakdown isp` row)",
          "required": false
        },
        {
          "name": "keyword",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose keyword contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Filter by landing page ID",
          "required": false
        },
        {
          "name": "method-of-promotion",
          "type": "string",
          "default": "",
          "usage": "Only direct-link clicks or only landing-page clicks: directlink, landingpage",
          "allowed_values": [
            "directlink",
            "landingpage"
          ],
          "required": false
        },
        {
          "name": "period",
          "shorthand": "p",
          "type": "string",
          "default": "",
          "usage": "Period: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "platform-id",
          "type": "string",
          "default": "",
          "usage": "Filter by platform (OS) ID (the id of a `--breakdown platform` row)",
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC account ID",
          "required": false
        },
        {
          "name": "ppc-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC network ID, or none for the clicks with no traffic source",
          "required": false
        },
        {
          "name": "referer",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose referring URL contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "region-id",
          "type": "string",
          "default": "",
          "usage": "Filter by region ID (the id of a `--breakdown region` row)",
          "required": false
        },
        {
          "name": "show",
          "type": "string",
          "default": "",
          "usage": "Which clicks count (default all): all, real, filtered, filtered_bot, leads; real = not filtered, filtered_bot = filtered as bots, leads = converted",
          "allowed_values": [
            "all",
            "real",
            "filtered",
            "filtered_bot",
            "leads"
          ],
          "required": false
        },
        {
          "name": "sort",
          "shorthand": "s",
          "type": "string",
          "default": "",
          "usage": "Sort by: day_of_week, total_clicks, total_click_throughs, total_leads, total_income, total_cost, total_net, epc, avg_cpc, conv_rate, roi, cpa (aliases: clicks=total_clicks, conversions=total_leads, cost=total_cost, income=total_income, leads=total_leads, net=total_net, profit=total_net, revenue=total_income)",
          "allowed_values": [
            "day_of_week",
            "total_clicks",
            "total_click_throughs",
            "total_leads",
            "total_income",
            "total_cost",
            "total_net",
            "epc",
            "avg_cpc",
            "conv_rate",
            "roi",
            "cpa"
          ],
          "value_aliases": {
            "clicks": "total_clicks",
            "conversions": "total_leads",
            "cost": "total_cost",
            "income": "total_income",
            "leads": "total_leads",
            "net": "total_net",
            "profit": "total_net",
            "revenue": "total_income"
          },
          "required": false
        },
        {
          "name": "sort-dir",
          "type": "string",
          "default": "",
          "usage": "Sort direction (also --sort-dir): ASC, DESC",
          "allowed_values": [
            "ASC",
            "DESC"
          ],
          "required": false
        },
        {
          "name": "text-ad-id",
          "type": "string",
          "default": "",
          "usage": "Filter by text ad ID",
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "End, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 report weekpart",
          "ui_pages": [
            "Overview › Week Parting"
          ],
          "phrases": [
            "weekparting",
            "weekday performance"
          ]
        }
      ]
    },
    {
      "path": "p202 report winners",
      "use": "winners",
      "short": "Rows to SCALE: profitable, converting keywords/geos; closers come back as CLOSER",
      "long": "Rows to SCALE from the classic (last-click) report: profitable and converting. Profit is the campaign's\nrecorded income less cost, or with --payout (your revenue per conversion) sales × payout less cost, the value the\nfirst-touch ROI below then uses too. Sales are counted with the Last touch model where the check can read it\n(a converted click can have several), so a source profitable only through repeat sales is listed too.\n\nEach SCALE row is then checked against the attribution report under a first-touch model, for the same dimension\nand range. A row that loses money under first touch comes back as CLOSER, with its first-touch ROI and assists:\nlast-click credits it with sales other rows started (retargeting, brand search and email often look like this),\nso more budget won't bring more new buyers. Check what feeds it before scaling.\n\nThe check runs for campaign, ppc_account (traffic source), landing_page, keyword and country, and needs a First\ntouch model (the first active one, or --first-touch-model) and an attribution:read key. When it can't run, the\nclassic winners are still listed with the reason on stderr. A filter other than the breakdown itself (an entity\nid, --keyword, --show, ...) turns it off; --no-attribution-check does too.",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by INTERNAL campaign id (from `campaign list`), not the public id in tracking URLs",
          "required": false
        },
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by affiliate network ID",
          "required": false
        },
        {
          "name": "breakdown",
          "shorthand": "b",
          "type": "string",
          "default": "keyword",
          "usage": "Dimension to triage: campaign, aff_network, ppc_account, ppc_network, landing_page, keyword, country, city, region, browser, platform, device, isp, text_ad, ip, referer, referer_url, device_type, c1, c2, c3, c4, utm_source, utm_medium, utm_campaign, utm_term, utm_content, rotator, rotator_rule (aliases: geo=country, lp=landing_page, network=aff_network, offer=campaign, referrer=referer, referrer_url=referer_url, rule=rotator_rule, source=ppc_account)",
          "allowed_values": [
            "campaign",
            "aff_network",
            "ppc_account",
            "ppc_network",
            "landing_page",
            "keyword",
            "country",
            "city",
            "region",
            "browser",
            "platform",
            "device",
            "isp",
            "text_ad",
            "ip",
            "referer",
            "referer_url",
            "device_type",
            "c1",
            "c2",
            "c3",
            "c4",
            "utm_source",
            "utm_medium",
            "utm_campaign",
            "utm_term",
            "utm_content",
            "rotator",
            "rotator_rule"
          ],
          "value_aliases": {
            "geo": "country",
            "lp": "landing_page",
            "network": "aff_network",
            "offer": "campaign",
            "referrer": "referer",
            "referrer_url": "referer_url",
            "rule": "rotator_rule",
            "source": "ppc_account"
          },
          "required": false
        },
        {
          "name": "browser-id",
          "type": "string",
          "default": "",
          "usage": "Filter by browser ID (the id of a `--breakdown browser` row)",
          "required": false
        },
        {
          "name": "country-id",
          "type": "string",
          "default": "",
          "usage": "Filter by country ID",
          "required": false
        },
        {
          "name": "device-type",
          "type": "string",
          "default": "",
          "usage": "Filter by device type ID: 1 Desktop, 2 Mobile, 3 Tablet, 4 Bot (the ids of `--breakdown device_type` rows)",
          "required": false
        },
        {
          "name": "first-touch-model",
          "type": "string",
          "default": "",
          "usage": "Attribution model id for the closer check (default: the first active First touch model)",
          "required": false
        },
        {
          "name": "ip",
          "type": "string",
          "default": "",
          "usage": "Only clicks from this one IP address, IPv4 or IPv6",
          "required": false
        },
        {
          "name": "isp-id",
          "type": "string",
          "default": "",
          "usage": "Filter by ISP/carrier ID (the id of a `--breakdown isp` row)",
          "required": false
        },
        {
          "name": "keyword",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose keyword contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Filter by landing page ID",
          "required": false
        },
        {
          "name": "max-cpc",
          "type": "float64",
          "default": "0",
          "usage": "Break-even CPC target (else payout × each row's CVR, from --payout or the campaign)",
          "required": false
        },
        {
          "name": "method-of-promotion",
          "type": "string",
          "default": "",
          "usage": "Only direct-link clicks or only landing-page clicks: directlink, landingpage",
          "allowed_values": [
            "directlink",
            "landingpage"
          ],
          "required": false
        },
        {
          "name": "min-clicks",
          "type": "float64",
          "default": "1",
          "usage": "Ignore rows with fewer than N clicks (significance floor)",
          "required": false
        },
        {
          "name": "no-attribution-check",
          "type": "bool",
          "default": "false",
          "usage": "List classic last-click winners only, without the first-touch closer check",
          "required": false
        },
        {
          "name": "payout",
          "type": "float64",
          "default": "0",
          "usage": "Revenue per conversion, e.g. your average order value: each row's break-even CPC is this × its conversion rate, and its profit (total_net) and first-touch ROI value each sale at this. Unlike --aff-campaign-id it doesn't filter the report, so the attribution check still runs",
          "required": false
        },
        {
          "name": "period",
          "shorthand": "p",
          "type": "string",
          "default": "",
          "usage": "Period: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "platform-id",
          "type": "string",
          "default": "",
          "usage": "Filter by platform (OS) ID (the id of a `--breakdown platform` row)",
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC account ID",
          "required": false
        },
        {
          "name": "ppc-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC network ID, or none for the clicks with no traffic source",
          "required": false
        },
        {
          "name": "referer",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose referring URL contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "region-id",
          "type": "string",
          "default": "",
          "usage": "Filter by region ID (the id of a `--breakdown region` row)",
          "required": false
        },
        {
          "name": "show",
          "type": "string",
          "default": "",
          "usage": "Which clicks count (default all): all, real, filtered, filtered_bot, leads; real = not filtered, filtered_bot = filtered as bots, leads = converted",
          "allowed_values": [
            "all",
            "real",
            "filtered",
            "filtered_bot",
            "leads"
          ],
          "required": false
        },
        {
          "name": "text-ad-id",
          "type": "string",
          "default": "",
          "usage": "Filter by text ad ID",
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "End, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
          "required": false
        }
      ]
    },
    {
      "path": "p202 rotator",
      "use": "rotator",
      "aliases": [
        "redirector"
      ],
      "short": "Manage redirectors (rotators and rules)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 rotator check",
      "use": "check [rotator_id]",
      "short": "Health-check rotators: flag missing defaults, ruleless rotators, empty rules",
      "long": "Exits non-zero if any checked rotator has a configuration problem, so it can gate a deploy.",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 rotator create",
      "use": "create",
      "short": "Create a new redirector/rotator for rule-based traffic splitting",
      "runnable": true,
      "flags": [
        {
          "name": "default-campaign",
          "type": "string",
          "default": "",
          "usage": "Default destination: one of your campaign ids",
          "required": false
        },
        {
          "name": "default-lp",
          "type": "string",
          "default": "",
          "usage": "Default destination: one of your landing page ids",
          "required": false
        },
        {
          "name": "default-url",
          "type": "string",
          "default": "",
          "usage": "Default destination: an http(s) URL (one of --default-url, --default-campaign, --default-lp)",
          "required": false
        },
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        },
        {
          "name": "name",
          "type": "string",
          "default": "",
          "usage": "Rotator name (required)",
          "required": true
        }
      ]
    },
    {
      "path": "p202 rotator criteria-values",
      "use": "criteria-values",
      "short": "List valid rotator criteria values (e.g. the exact country strings)",
      "long": "Prints the value strings rules expect, so you never guess the `United States(US)` format. Filter with --search.",
      "runnable": true,
      "flags": [
        {
          "name": "search",
          "type": "string",
          "default": "",
          "usage": "Filter values by substring",
          "required": false
        },
        {
          "name": "type",
          "type": "string",
          "default": "country",
          "usage": "Criteria type (country)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 rotator delete",
      "use": "delete <id>",
      "short": "Delete a redirector/rotator and all its routing rules",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated rotator IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 rotator get",
      "use": "get <id>",
      "short": "Get a redirector/rotator and its routing rules by ID",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 rotator list",
      "use": "list",
      "short": "List all redirectors/rotators",
      "runnable": true,
      "flags": [
        {
          "name": "all",
          "type": "bool",
          "default": "false",
          "usage": "Fetch all rows across pages",
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 rotator list",
          "ui_pages": [
            "Setup › Redirector"
          ],
          "phrases": [
            "rotators",
            "split test offers",
            "redirect rules"
          ]
        }
      ]
    },
    {
      "path": "p202 rotator rule-create",
      "use": "rule-create <rotator_id>",
      "short": "Add a routing rule to a redirector/rotator (criteria + redirect targets)",
      "runnable": true,
      "flags": [
        {
          "name": "country",
          "type": "string",
          "default": "",
          "usage": "Sugar: ISO country code (e.g. US) -> a country `is` criterion; avoids hand-writing --criteria-json",
          "required": false
        },
        {
          "name": "criteria-json",
          "type": "string",
          "default": "",
          "usage": "Criteria JSON array, e.g. [{\"type\":\"country\",\"statement\":\"is\",\"value\":\"United States(US)\"}]",
          "required": false
        },
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        },
        {
          "name": "redirect-campaign",
          "type": "string",
          "default": "",
          "usage": "Sugar: redirect to this campaign id at full weight; avoids hand-writing --redirects-json",
          "required": false
        },
        {
          "name": "redirects-json",
          "type": "string",
          "default": "",
          "usage": "Redirects JSON array, e.g. [{\"redirect_campaign\":\"90008\",\"weight\":\"100\",\"name\":\"A\"}]",
          "required": false
        },
        {
          "name": "rule-name",
          "type": "string",
          "default": "",
          "usage": "Rule name (required)",
          "required": true
        },
        {
          "name": "splittest",
          "type": "string",
          "default": "",
          "usage": "Enable split test: 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "status",
          "type": "string",
          "default": "",
          "usage": "Rule status: 1 active (the default), 0 created paused: 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        }
      ]
    },
    {
      "path": "p202 rotator rule-delete",
      "use": "rule-delete <rotator_id> <rule_id>",
      "short": "Delete a routing rule from a redirector/rotator",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated rule IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 rotator rule-update",
      "use": "rule-update <rotator_id> <rule_id>",
      "short": "Update a routing rule on a redirector/rotator",
      "runnable": true,
      "flags": [
        {
          "name": "criteria-json",
          "type": "string",
          "default": "",
          "usage": "Criteria JSON array, e.g. [{\"type\":\"country\",\"statement\":\"is\",\"value\":\"United States(US)\"}]",
          "required": false
        },
        {
          "name": "redirects-json",
          "type": "string",
          "default": "",
          "usage": "Redirects JSON array, e.g. [{\"redirect_url\":\"...\",\"weight\":\"50\",\"name\":\"A\"}]",
          "required": false
        },
        {
          "name": "rule-id",
          "type": "string",
          "default": "",
          "usage": "Rule ID (alternative to the second positional arg)",
          "required": false
        },
        {
          "name": "rule-name",
          "type": "string",
          "default": "",
          "usage": "Rule name",
          "required": false
        },
        {
          "name": "splittest",
          "type": "string",
          "default": "",
          "usage": "Enable split test: 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "status",
          "type": "string",
          "default": "",
          "usage": "Rule status (1 = active): 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        }
      ]
    },
    {
      "path": "p202 rotator stats",
      "use": "stats <id>",
      "short": "Show a rotator's performance: its totals, each rule, and its default (clicks no rule matched)",
      "long": "The Overview's Rotator Breakdown for one rotator, from GET /rotators/{id}/stats: clicks, leads, income,\ncost, net, EPC, conversion rate and ROI for the rotator, for each of its rules (the rule the click matched),\nand for its default. The rules and the default add up to the totals; a rule since deleted that still has\nclicks in the window is listed with deleted: true. Takes the window and the filters every report takes.\nNeeds a key with read scope on rotators and reports.",
      "example": "p202 rotator stats 3 --period last30\n  p202 rotator stats 3 --period yesterday --show real",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by INTERNAL campaign id (from `campaign list`), not the public id in tracking URLs",
          "required": false
        },
        {
          "name": "aff-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by affiliate network ID",
          "required": false
        },
        {
          "name": "browser-id",
          "type": "string",
          "default": "",
          "usage": "Filter by browser ID (the id of a `--breakdown browser` row)",
          "required": false
        },
        {
          "name": "country-id",
          "type": "string",
          "default": "",
          "usage": "Filter by country ID",
          "required": false
        },
        {
          "name": "device-type",
          "type": "string",
          "default": "",
          "usage": "Filter by device type ID: 1 Desktop, 2 Mobile, 3 Tablet, 4 Bot (the ids of `--breakdown device_type` rows)",
          "required": false
        },
        {
          "name": "ip",
          "type": "string",
          "default": "",
          "usage": "Only clicks from this one IP address, IPv4 or IPv6",
          "required": false
        },
        {
          "name": "isp-id",
          "type": "string",
          "default": "",
          "usage": "Filter by ISP/carrier ID (the id of a `--breakdown isp` row)",
          "required": false
        },
        {
          "name": "keyword",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose keyword contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Filter by landing page ID",
          "required": false
        },
        {
          "name": "method-of-promotion",
          "type": "string",
          "default": "",
          "usage": "Only direct-link clicks or only landing-page clicks: directlink, landingpage",
          "allowed_values": [
            "directlink",
            "landingpage"
          ],
          "required": false
        },
        {
          "name": "period",
          "shorthand": "p",
          "type": "string",
          "default": "",
          "usage": "Period: today, yesterday, last7, last14, last30, last90, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "last90",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "platform-id",
          "type": "string",
          "default": "",
          "usage": "Filter by platform (OS) ID (the id of a `--breakdown platform` row)",
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC account ID",
          "required": false
        },
        {
          "name": "ppc-network-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC network ID, or none for the clicks with no traffic source",
          "required": false
        },
        {
          "name": "referer",
          "type": "string",
          "default": "",
          "usage": "Only clicks whose referring URL contains this text (case-insensitive)",
          "required": false
        },
        {
          "name": "region-id",
          "type": "string",
          "default": "",
          "usage": "Filter by region ID (the id of a `--breakdown region` row)",
          "required": false
        },
        {
          "name": "show",
          "type": "string",
          "default": "",
          "usage": "Which clicks count (default all): all, real, filtered, filtered_bot, leads; real = not filtered, filtered_bot = filtered as bots, leads = converted",
          "allowed_values": [
            "all",
            "real",
            "filtered",
            "filtered_bot",
            "leads"
          ],
          "required": false
        },
        {
          "name": "text-ad-id",
          "type": "string",
          "default": "",
          "usage": "Filter by text ad ID",
          "required": false
        },
        {
          "name": "time-from",
          "type": "string",
          "default": "",
          "usage": "Start: unix seconds, a date (2026-10-01, from its first second in the account's timezone) or a time with its offset (2026-10-01T09:30:00Z)",
          "required": false
        },
        {
          "name": "time-to",
          "type": "string",
          "default": "",
          "usage": "End, inclusive: unix seconds, a date (2026-10-01, through its last second in the account's timezone) or a time with its offset",
          "required": false
        }
      ]
    },
    {
      "path": "p202 rotator test",
      "use": "test <rotator_id>",
      "short": "Show where a rotator routes traffic per geo (local rule evaluation)",
      "long": "Evaluates the rotator's active rules locally and prints the destination a\nvisitor from each --geo would reach. --explain shows per-criteria pass/fail,\nwhich surfaces the Name(CC) country-format mismatches that silently break rules.",
      "runnable": true,
      "flags": [
        {
          "name": "explain",
          "type": "bool",
          "default": "false",
          "usage": "Show per-criteria pass/fail for each geo",
          "required": false
        },
        {
          "name": "geo",
          "type": "string",
          "default": "",
          "usage": "Comma-separated country codes to evaluate (default: a tier-1+rest sample)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 rotator trace",
      "use": "trace <rotator_id>",
      "short": "Show the trackers that feed a rotator and where it routes",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 rotator update",
      "use": "update <id>",
      "short": "Update a redirector/rotator's name or defaults",
      "runnable": true,
      "flags": [
        {
          "name": "default-campaign",
          "type": "string",
          "default": "",
          "usage": "New default: one of your campaign ids; replaces the current default",
          "required": false
        },
        {
          "name": "default-lp",
          "type": "string",
          "default": "",
          "usage": "New default: one of your landing page ids; replaces the current default",
          "required": false
        },
        {
          "name": "default-url",
          "type": "string",
          "default": "",
          "usage": "New default: an http(s) URL; replaces the current default, whatever its kind",
          "required": false
        },
        {
          "name": "name",
          "type": "string",
          "default": "",
          "usage": "Rotator name",
          "required": false
        }
      ]
    },
    {
      "path": "p202 search",
      "use": "search <what you want to do>",
      "short": "Find the command for a task: ranks commands, flags, flag values and UI pages by your words (offline)",
      "long": "Searches every command's name, aliases, description, examples, flags, the values\nits flags accept, and the tasks it runs: the web UI page that does the same (\"Spy\",\n\"Update CPC\") and the words people use for it (\"realtime traffic\"). Lists the best\nmatches (5 by default), best first, each with why it matched, the share of your\nwords it matched (coverage) and a command line to try. Plural forms, common\nsynonyms (referrer/referer, offer/campaign, dead/broken, undo/revert, link/url),\ninflected forms (imported, charged) and split words (real time, real-time) match.\nMisspellings are not corrected: a word no command mentions is listed above the\nresults (unknown_terms in JSON); the commands lack it or call it something else.\nNo server is contacted.\n\ngood_match says whether the first is a confident answer (it matched at least three\nquarters of your words); a table says so above the list when it is not, and\n--quiet prints that first command alone, and only for a confident answer, so a\nscript never runs a guess. It fails (exit 1) only when nothing matches, or when\nthe words name a web UI page no command does, and then it says where that is\ndone instead.\n\nSearch matches words, not meaning: on 36 tasks as an agent phrased them, written\nbefore this version was measured, the first result was right for 27 and the first\nfive held the right command for 34. A model reading `p202 commands --brief` chose\nright first for 34: an agent choosing a command does better reading the catalog.",
      "example": "p202 search breakdown by browser\n  p202 search realtime traffic\n  p202 search dead links --json\n  p202 search undo url change",
      "runnable": true,
      "flags": [
        {
          "name": "limit",
          "type": "int",
          "default": "5",
          "usage": "Most results to show",
          "required": false
        }
      ]
    },
    {
      "path": "p202 shell",
      "use": "shell",
      "short": "Interactive shell with session state and batch execution",
      "long": "Start an interactive shell for running multiple commands in a persistent session.\n\nFeatures:\n  - Session state: command results stored in $_ (last result)\n  - Profile switching: \"use <profile>\" changes active profile without restarting\n  - Batch mode: -c \"cmd1; cmd2\" or piped stdin for AI agent integration\n  - Non-fatal errors: errors display but don't exit the session\n\nRequires a valid API key. Access is verified against the server capabilities endpoint.\n\nExamples:\n  p202 shell                              # interactive mode\n  p202 shell -c \"campaign list; health\"   # batch: run commands and exit\n  echo \"health\" | p202 shell              # batch: read from stdin\n  p202 shell --script commands.txt        # batch: read from file",
      "runnable": true,
      "flags": [
        {
          "name": "command",
          "shorthand": "c",
          "type": "string",
          "default": "",
          "usage": "Execute commands and exit (semicolon-separated)",
          "required": false
        },
        {
          "name": "script",
          "type": "string",
          "default": "",
          "usage": "Read and execute commands from a file",
          "required": false
        },
        {
          "name": "stop-on-error",
          "type": "bool",
          "default": "false",
          "usage": "Stop batch execution on first error",
          "required": false
        }
      ]
    },
    {
      "path": "p202 sync",
      "use": "sync <entity|all>",
      "short": "Sync entities from one profile to another",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Show sync actions without writing",
          "required": false
        },
        {
          "name": "force-update",
          "type": "bool",
          "default": "false",
          "usage": "Update mismatched target records",
          "required": false
        },
        {
          "name": "from",
          "type": "string",
          "default": "",
          "usage": "Source profile name (alias: --source)",
          "required": false
        },
        {
          "name": "skip-errors",
          "type": "bool",
          "default": "false",
          "usage": "Continue processing after record-level failures; exits 5 when any record failed, and a 401 or 403 still stops it",
          "required": false
        },
        {
          "name": "source",
          "type": "string",
          "default": "",
          "usage": "Source profile name (alias of --from)",
          "required": false
        },
        {
          "name": "target",
          "type": "string",
          "default": "",
          "usage": "Target profile name (alias of --to)",
          "required": false
        },
        {
          "name": "to",
          "type": "string",
          "default": "",
          "usage": "Target profile name (alias: --target)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 sync history",
      "use": "history",
      "short": "Show sync history between profiles",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Show sync actions without writing",
          "required": false
        },
        {
          "name": "force-update",
          "type": "bool",
          "default": "false",
          "usage": "Update mismatched target records",
          "required": false
        },
        {
          "name": "from",
          "type": "string",
          "default": "",
          "usage": "Source profile name (alias: --source)",
          "required": false
        },
        {
          "name": "skip-errors",
          "type": "bool",
          "default": "false",
          "usage": "Continue processing after record-level failures; exits 5 when any record failed, and a 401 or 403 still stops it",
          "required": false
        },
        {
          "name": "source",
          "type": "string",
          "default": "",
          "usage": "Source profile name (alias of --from)",
          "required": false
        },
        {
          "name": "target",
          "type": "string",
          "default": "",
          "usage": "Target profile name (alias of --to)",
          "required": false
        },
        {
          "name": "to",
          "type": "string",
          "default": "",
          "usage": "Target profile name (alias: --target)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 sync status",
      "use": "status",
      "short": "Show sync status and drift summary between profiles",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Show sync actions without writing",
          "required": false
        },
        {
          "name": "force-update",
          "type": "bool",
          "default": "false",
          "usage": "Update mismatched target records",
          "required": false
        },
        {
          "name": "from",
          "type": "string",
          "default": "",
          "usage": "Source profile name (alias: --source)",
          "required": false
        },
        {
          "name": "skip-errors",
          "type": "bool",
          "default": "false",
          "usage": "Continue processing after record-level failures; exits 5 when any record failed, and a 401 or 403 still stops it",
          "required": false
        },
        {
          "name": "source",
          "type": "string",
          "default": "",
          "usage": "Source profile name (alias of --from)",
          "required": false
        },
        {
          "name": "target",
          "type": "string",
          "default": "",
          "usage": "Target profile name (alias of --to)",
          "required": false
        },
        {
          "name": "to",
          "type": "string",
          "default": "",
          "usage": "Target profile name (alias: --target)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 system",
      "use": "system",
      "short": "System information and diagnostics",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 system cron",
      "use": "cron",
      "short": "Show whether cron is ticking: rows and last run per job type",
      "long": "Summarizes 202_cronjobs: per cronjob_type, its row count and last run (time\nand age), then the last execution recorded in 202_cronjob_logs with its age.\nRows record the slot a job ran for: the daily row is noon of its day (so\nbefore noon it reads as later today), the hourly row the start of its hour.\n\nThe column is char(5): hour is the hourly tier, secon the per-minute one (a\nrow a minute, by design). hourl is 'hourly' cut short, as development builds\nbetween 1.9.55 and 1.9.76 wrote it: their check never matched, so that tier\nran every minute; past 100 such rows a note says so.\n\nLike `p202 rotator check`, it exits 5 (partial_failure) when the last\nexecution is older than 5 minutes (stale) or none is recorded (never_ran),\nwith the summary still printed on stdout.\n\n--raw prints every row as the server returns it; under --json it adds the\nserver's jobs and recent_logs arrays to the summary object.",
      "example": "p202 system cron\n  p202 system cron --json\n  p202 system cron --raw --json",
      "runnable": true,
      "flags": [
        {
          "name": "raw",
          "type": "bool",
          "default": "false",
          "usage": "Print every 202_cronjobs row as the server returns it (with --json: add jobs and recent_logs to the summary)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 system dataengine",
      "use": "dataengine",
      "short": "Show data engine status",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 system db-stats",
      "use": "db-stats",
      "short": "Show database table statistics",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 system errors",
      "use": "errors",
      "short": "Show recent system errors",
      "runnable": true,
      "flags": [
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max errors to show",
          "required": false
        }
      ]
    },
    {
      "path": "p202 system health",
      "use": "health",
      "short": "Check system health and the TLS certificate (no auth required)",
      "long": "Calls the unauthenticated system/health endpoint and, for an https base URL,\nchecks the TLS certificate of its host first: a verified handshake on its own\nconnection, with no HTTP request, so an expired certificate is reported as\none instead of as a network error from the API call.\n\ntls_status: ok, expiring (expires within --cert-warn-days), expired,\nhostname_mismatch, unknown_authority, invalid, unreachable; not_used for an\nhttp:// URL. tls_not_after, tls_days_left and tls_issuer describe the\ncertificate the server sent (null when none arrived); tls_detail says why.\n\nLike `p202 rotator check`, it exits 5 (partial_failure) when tls_status is\nanything but ok or not_used, with the health object still printed on stdout.\nWhen only the API call fails, it exits as that error does (3 network, 4 server).",
      "example": "p202 system health\n  p202 system health --cert-warn-days 30 --json",
      "runnable": true,
      "flags": [
        {
          "name": "cert-warn-days",
          "type": "int",
          "default": "21",
          "usage": "Report the certificate as expiring when it expires within this many days (0 turns the warning off)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 system info",
      "use": "info",
      "short": "What Account › Settings shows: versions, PHP limits, memcache, clicks recorded, database size, cron, DataEngine",
      "long": "The Prosper202 code and database versions (database_upgrade_needed when they differ), PHP\nand MySQL versions, memcache, the PHP limits uploads and long reports run under, clicks\nrecorded to date, database size, when the cron job last ran, and the DataEngine's progress.\nWhether a newer release exists is not reported: the UI asks a remote service for that.\n\nNeeds an Admin or Super user key whose role has access_to_settings (as Account › Settings asks), and system:read.",
      "example": "p202 system info\n  p202 system info --json",
      "runnable": true,
      "flags": [],
      "tasks": [
        {
          "run": "p202 system info",
          "ui_pages": [
            "Settings"
          ],
          "phrases": [
            "install settings",
            "versions",
            "database size"
          ]
        }
      ]
    },
    {
      "path": "p202 system integrations",
      "use": "integrations",
      "short": "The URLs to paste into ClickBank, JVZoo, Zaxaa, Slack and PayKickstart for this install",
      "long": "Each integration's notification URL (INS, IPN, ZPN, webhook) on this install's tracking base,\nand whether its secret is stored (secret_stored; set it with `p202 user prefs update <user_id>`). The\nsecrets themselves are never shown. --json adds base_url; --wide shows the URLs in full.\n\nNeeds an Admin or Super user key whose role has access_to_api_integrations (as Account › API integrations asks), and system:read.",
      "example": "p202 system integrations\n  p202 system integrations --json",
      "runnable": true,
      "flags": [],
      "tasks": [
        {
          "run": "p202 system integrations",
          "ui_pages": [
            "3rd Party API Integrations"
          ],
          "phrases": [
            "clickbank url",
            "jvzoo url",
            "instant notification url"
          ]
        }
      ]
    },
    {
      "path": "p202 system isp-lookup",
      "use": "isp-lookup",
      "short": "MaxMind ISP and carrier lookup on your trackers' clicks: show, enable, disable",
      "long": "Account › Settings › ISP and carrier lookup. It needs the MaxMind ISP database\n(GeoIP2-ISP.mmdb, or legacy GeoIPISP.dat) in the directory `show` names. The switch is the\nkey's own user's, and applies to that user's trackers; live traffic picks a change up within\nfive minutes.\n\nNeeds an Admin or Super user key whose role has access_to_settings (as Account › Settings asks).",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 system isp-lookup disable",
      "use": "disable",
      "short": "Turn ISP and carrier lookup off",
      "long": "Cannot be staged. Needs an Admin or Super user key whose role has access_to_settings (as Account › Settings asks), and system:write.",
      "example": "p202 system isp-lookup disable",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 system isp-lookup enable",
      "use": "enable",
      "short": "Turn ISP and carrier lookup on (refused while the ISP database is missing)",
      "long": "Cannot be staged. Needs an Admin or Super user key whose role has access_to_settings (as Account › Settings asks), and system:write.",
      "example": "p202 system isp-lookup enable",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 system isp-lookup show",
      "use": "show",
      "short": "Whether ISP lookup is on, and whether the ISP database it needs is in place",
      "example": "p202 system isp-lookup show --json",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 system login-log",
      "use": "login-log",
      "short": "Sign-in attempts to this install, newest first: who, when, from which IP, passed or failed",
      "long": "The attempts Account › Settings lists (its last 50 by default; --limit up to 500). Each row\nis the user name typed, the time (login_time, unix seconds), the IP address and whether it\npassed (login_success). Throttled and token-refused attempts are not recorded.\n\nNeeds an Admin or Super user key whose role has access_to_settings (as Account › Settings asks), and system:read.",
      "example": "p202 system login-log\n  p202 system login-log --limit 200 --json",
      "runnable": true,
      "flags": [
        {
          "name": "limit",
          "type": "string",
          "default": "",
          "usage": "How many attempts to list, 1-500 (default 50, as on the page)",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 system login-log",
          "phrases": [
            "sign-in attempts",
            "login history",
            "failed logins"
          ]
        }
      ]
    },
    {
      "path": "p202 system metrics",
      "use": "metrics",
      "short": "Server metrics: sync counters, the sync job queue (queued, running, lag), recent spans and active alerts",
      "long": "GET /system/metrics. alerts.active lists a failure spike or a queue lag past its threshold\n(P202_ALERT_FAILURE_SPIKE, P202_ALERT_QUEUE_LAG_SECONDS on the server).\n\nNeeds an Admin or Super user key with system:read.",
      "example": "p202 system metrics --json",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 system retention",
      "use": "retention",
      "short": "Click-data retention: automatic deletion after N days, and a one-off deletion before a date",
      "long": "Account › Settings › Click data, for the whole install (every account's clicks). The cron job\ndoes the deleting, in batches: `show` says what is set, `set` changes the automatic deletion,\n`delete-before` schedules the one-off deletion. Setup data (campaigns, trackers, landing\npages) is never deleted.\n\nNeeds an Admin or Super user key whose role has access_to_settings (as Account › Settings asks).",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 system retention delete-before",
      "use": "delete-before --date YYYY-MM-DD",
      "short": "Schedule the deletion of all click data from before a day (irreversible; previews and asks first)",
      "long": "Schedules what Account › Settings › Advanced › \"Delete click data from before\" does: the\ncron job deletes, in batches, every click of every account on this install all of whose\nvisits were recorded before midnight that begins --date (the account's time zone), from\nevery click table. A click visited again that day or later is kept whole. Setup data is\nkept. It cannot be undone.\n\nIt always previews first (POST …/delete-before?dry_run=1) and says how many clicks and rows\nwould go now, then asks (--force skips the question, never the preview; --dry-run ends with\nthe preview). The write carries the cutoff_time the preview named and the server schedules\nonly that, so it never schedules a different cutoff than was shown. Cannot be staged.\n\nNeeds an Admin or Super user key whose role has access_to_settings (as Account › Settings asks), and system:write.",
      "example": "p202 system retention delete-before --date 2026-01-01 --dry-run\n  p202 system retention delete-before --date 2026-01-01",
      "runnable": true,
      "flags": [
        {
          "name": "date",
          "type": "string",
          "default": "",
          "usage": "Delete click data from before this day, YYYY-MM-DD in the account's time zone (required)",
          "required": true
        },
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what would be deleted and schedule nothing",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Schedule it without asking (the preview still runs)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 system retention set",
      "use": "set --days <n>",
      "short": "Set the automatic click-data deletion to N days (0 keeps every click); asks when it would keep less",
      "long": "Sets how many days of click data the cron job's automatic deletion keeps (0 to 36500; 0 keeps\neverything), for the whole install. When the new value keeps less than the current one (turning\ndeletion on, or a shorter period) it asks first, because what the cron job deletes cannot be\nrecovered; --force skips the question. Cannot be staged.\n\nNeeds an Admin or Super user key whose role has access_to_settings (as Account › Settings asks), and system:write.",
      "example": "p202 system retention set --days 180\n  p202 system retention set --days 0",
      "runnable": true,
      "flags": [
        {
          "name": "days",
          "type": "string",
          "default": "",
          "usage": "Days of click data to keep, 0-36500 (0 keeps every click) (required)",
          "required": true
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Set it without asking, even when it deletes more",
          "required": false
        }
      ]
    },
    {
      "path": "p202 system retention show",
      "use": "show",
      "short": "Show the automatic deletion (auto_delete_days; 0 keeps everything) and any scheduled one-off deletion",
      "long": "auto_delete_days: click data older than this many days is deleted each night (0 keeps it).\nscheduled_deletion: a one-off deletion `delete-before` scheduled — the cron job deletes every\nclick all of whose visits were recorded before cutoff_time (midnight that begins `before`);\nclicks_remaining counts those still there. An install that scheduled one before cutoff_time\nexisted shows through_click_id instead (cutoff_time null): the clicks below that id go. null\nwhen none was scheduled.",
      "example": "p202 system retention show --json",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 system version",
      "use": "version",
      "short": "Show Prosper202 and system version info",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 text-ad",
      "use": "text-ad",
      "short": "Manage text ads (ad creatives with headline, description, and display URL)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 text-ad create",
      "use": "create",
      "short": "Create a new text-ad",
      "example": "p202 text-ad create --text-ad-name <text_ad_name> --text-ad-headline <text_ad_headline> --text-ad-description <text_ad_description> --text-ad-display-url <text_ad_display_url> --json",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Campaign ID (from `p202 campaign list`)",
          "required": false
        },
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Landing page ID (from `p202 landing-page list`)",
          "required": false
        },
        {
          "name": "text-ad-description",
          "type": "string",
          "default": "",
          "usage": "Description text (required)",
          "required": true
        },
        {
          "name": "text-ad-display-url",
          "type": "string",
          "default": "",
          "usage": "Display URL (required)",
          "required": true
        },
        {
          "name": "text-ad-headline",
          "type": "string",
          "default": "",
          "usage": "Headline (required)",
          "required": true
        },
        {
          "name": "text-ad-name",
          "type": "string",
          "default": "",
          "usage": "Text ad name (required)",
          "required": true
        },
        {
          "name": "text-ad-type",
          "type": "string",
          "default": "",
          "usage": "Text ad type (integer)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 text-ad delete",
      "use": "delete <id>",
      "short": "Delete a text-ad",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated text-ad IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 text-ad get",
      "use": "get <id>",
      "short": "Get a text-ad by ID",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 text-ad list",
      "use": "list",
      "short": "List text ads (ad creatives with headline, description, and display URL)",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by campaign ID (from `p202 campaign list`)",
          "required": false
        },
        {
          "name": "all",
          "type": "bool",
          "default": "false",
          "usage": "Fetch all rows across pages",
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "page",
          "type": "string",
          "default": "",
          "usage": "Page number",
          "required": false
        },
        {
          "name": "resolve-names",
          "type": "bool",
          "default": "false",
          "usage": "Resolve foreign key IDs to names",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 text-ad list",
          "ui_pages": [
            "Setup › Text Ads"
          ]
        }
      ]
    },
    {
      "path": "p202 text-ad update",
      "use": "update <id>",
      "short": "Update a text-ad",
      "example": "p202 text-ad update <id from p202 text-ad list> --text-ad-name <new value> --json\n  (only the flags given are sent; the rest of the text-ad is unchanged)",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Campaign ID (from `p202 campaign list`)",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Landing page ID (from `p202 landing-page list`)",
          "required": false
        },
        {
          "name": "text-ad-description",
          "type": "string",
          "default": "",
          "usage": "Description text",
          "required": false
        },
        {
          "name": "text-ad-display-url",
          "type": "string",
          "default": "",
          "usage": "Display URL",
          "required": false
        },
        {
          "name": "text-ad-headline",
          "type": "string",
          "default": "",
          "usage": "Headline",
          "required": false
        },
        {
          "name": "text-ad-name",
          "type": "string",
          "default": "",
          "usage": "Text ad name",
          "required": false
        },
        {
          "name": "text-ad-type",
          "type": "string",
          "default": "",
          "usage": "Text ad type (integer)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 tracker",
      "use": "tracker",
      "short": "Manage trackers (tracking links that tie a traffic source to a campaign and landing page)",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 tracker bulk-urls",
      "use": "bulk-urls",
      "short": "Fetch tracking URLs for multiple trackers",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by campaign ID",
          "required": false
        },
        {
          "name": "c1",
          "type": "string",
          "default": "",
          "usage": "Value for c1 in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "c2",
          "type": "string",
          "default": "",
          "usage": "Value for c2 in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "c3",
          "type": "string",
          "default": "",
          "usage": "Value for c3 in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "c4",
          "type": "string",
          "default": "",
          "usage": "Value for c4 in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "concurrency",
          "type": "int",
          "default": "5",
          "usage": "Number of concurrent URL fetches",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Filter by landing page ID",
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC account ID",
          "required": false
        },
        {
          "name": "t202b",
          "type": "string",
          "default": "",
          "usage": "Value for t202b in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "t202kw",
          "type": "string",
          "default": "",
          "usage": "Value for t202kw in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "t202ref",
          "type": "string",
          "default": "",
          "usage": "Value for t202ref in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "utm-campaign",
          "type": "string",
          "default": "",
          "usage": "Value for utm_campaign in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "utm-content",
          "type": "string",
          "default": "",
          "usage": "Value for utm_content in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "utm-medium",
          "type": "string",
          "default": "",
          "usage": "Value for utm_medium in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "utm-source",
          "type": "string",
          "default": "",
          "usage": "Value for utm_source in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "utm-term",
          "type": "string",
          "default": "",
          "usage": "Value for utm_term in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        }
      ]
    },
    {
      "path": "p202 tracker check",
      "use": "check [tracker_id]",
      "short": "Resolve tracker links and flag blank/dropped destinations",
      "long": "Exits non-zero if any checked tracker resolves to a blank Location or a non-3xx status.",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 tracker create",
      "use": "create",
      "short": "Create a new tracker",
      "example": "p202 tracker create --aff-campaign-id <id from p202 campaign list> --json",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Campaign ID (from `p202 campaign list`); 0 for a link to a redirector (--rotator-id) or an advanced landing page (required)",
          "required": true
        },
        {
          "name": "click-cloaking",
          "type": "string",
          "default": "",
          "usage": "Cloaking: 1 on, 0 off, -1 use the campaign's setting: -1, 0, 1",
          "allowed_values": [
            "-1",
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "click-cpa",
          "type": "string",
          "default": "",
          "usage": "Cost per action, 0-99.99999; on update, makes the tracker CPA and clears its cost per click. Not with --click-cpc",
          "required": false
        },
        {
          "name": "click-cpc",
          "type": "string",
          "default": "",
          "usage": "Cost per click, 0-99.99999; on update, makes the tracker CPC and clears its cost per action",
          "required": false
        },
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Landing page ID (from `p202 landing-page list`)",
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "PPC account ID (from `p202 ppc-account list`)",
          "required": false
        },
        {
          "name": "rotator-id",
          "type": "string",
          "default": "",
          "usage": "Rotator ID (from `p202 rotator list`)",
          "required": false
        },
        {
          "name": "text-ad-id",
          "type": "string",
          "default": "",
          "usage": "Text ad ID (from `p202 text-ad list`)",
          "required": false
        },
        {
          "name": "tracker-id-public",
          "type": "string",
          "default": "",
          "usage": "Public tracker ID",
          "required": false
        }
      ]
    },
    {
      "path": "p202 tracker create-with-url",
      "use": "create-with-url",
      "short": "Create a tracker and return its tracking URL",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Campaign ID (from `p202 campaign list`); 0 for a link to a redirector (--rotator-id) or an advanced landing page",
          "required": false
        },
        {
          "name": "c1",
          "type": "string",
          "default": "",
          "usage": "Value for c1 in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "c2",
          "type": "string",
          "default": "",
          "usage": "Value for c2 in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "c3",
          "type": "string",
          "default": "",
          "usage": "Value for c3 in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "c4",
          "type": "string",
          "default": "",
          "usage": "Value for c4 in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "click-cloaking",
          "type": "string",
          "default": "",
          "usage": "Cloaking: 1 on, 0 off, -1 use the campaign's setting: -1, 0, 1",
          "allowed_values": [
            "-1",
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "click-cpa",
          "type": "string",
          "default": "",
          "usage": "Cost per action, 0-99.99999; on update, makes the tracker CPA and clears its cost per click. Not with --click-cpc",
          "required": false
        },
        {
          "name": "click-cpc",
          "type": "string",
          "default": "",
          "usage": "Cost per click, 0-99.99999; on update, makes the tracker CPC and clears its cost per action",
          "required": false
        },
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Landing page ID",
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "PPC account ID",
          "required": false
        },
        {
          "name": "rotator-id",
          "type": "string",
          "default": "",
          "usage": "Rotator ID",
          "required": false
        },
        {
          "name": "t202b",
          "type": "string",
          "default": "",
          "usage": "Value for t202b in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "t202kw",
          "type": "string",
          "default": "",
          "usage": "Value for t202kw in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "t202ref",
          "type": "string",
          "default": "",
          "usage": "Value for t202ref in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "text-ad-id",
          "type": "string",
          "default": "",
          "usage": "Text ad ID",
          "required": false
        },
        {
          "name": "tracker-id-public",
          "type": "string",
          "default": "",
          "usage": "Public tracker ID",
          "required": false
        },
        {
          "name": "utm-campaign",
          "type": "string",
          "default": "",
          "usage": "Value for utm_campaign in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "utm-content",
          "type": "string",
          "default": "",
          "usage": "Value for utm_content in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "utm-medium",
          "type": "string",
          "default": "",
          "usage": "Value for utm_medium in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "utm-source",
          "type": "string",
          "default": "",
          "usage": "Value for utm_source in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "utm-term",
          "type": "string",
          "default": "",
          "usage": "Value for utm_term in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 tracker create-with-url",
          "ui_pages": [
            "Setup › Get Links"
          ],
          "phrases": [
            "tracking link",
            "generate a tracking link",
            "campaign link"
          ]
        }
      ]
    },
    {
      "path": "p202 tracker delete",
      "use": "delete <id>",
      "short": "Delete a tracker",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated tracker IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 tracker get",
      "use": "get <id>",
      "short": "Get a tracker by ID",
      "long": "Get a tracker by id. Accepts the internal tracker_id (from `tracker list`). If you pass the\npublic tracker_id_public (the value in tracking links / the UI), it is resolved automatically;\nuse --public to force the public lookup.",
      "runnable": true,
      "flags": [
        {
          "name": "public",
          "type": "bool",
          "default": "false",
          "usage": "Treat the id as the public tracker_id_public",
          "required": false
        }
      ]
    },
    {
      "path": "p202 tracker get-url",
      "use": "get-url <id>",
      "short": "Get tracking URL for a tracker",
      "long": "Accepts the internal tracker_id (from `tracker list`). If you pass the\npublic tracker_id_public (the value in the tracking link), it is resolved\nautomatically.",
      "runnable": true,
      "flags": [
        {
          "name": "c1",
          "type": "string",
          "default": "",
          "usage": "Value for c1 in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "c2",
          "type": "string",
          "default": "",
          "usage": "Value for c2 in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "c3",
          "type": "string",
          "default": "",
          "usage": "Value for c3 in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "c4",
          "type": "string",
          "default": "",
          "usage": "Value for c4 in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "t202b",
          "type": "string",
          "default": "",
          "usage": "Value for t202b in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "t202kw",
          "type": "string",
          "default": "",
          "usage": "Value for t202kw in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "t202ref",
          "type": "string",
          "default": "",
          "usage": "Value for t202ref in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "utm-campaign",
          "type": "string",
          "default": "",
          "usage": "Value for utm_campaign in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "utm-content",
          "type": "string",
          "default": "",
          "usage": "Value for utm_content in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "utm-medium",
          "type": "string",
          "default": "",
          "usage": "Value for utm_medium in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "utm-source",
          "type": "string",
          "default": "",
          "usage": "Value for utm_source in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        },
        {
          "name": "utm-term",
          "type": "string",
          "default": "",
          "usage": "Value for utm_term in the link, as given (e.g. your traffic source's macro); default: the traffic source's own variable",
          "required": false
        }
      ]
    },
    {
      "path": "p202 tracker list",
      "use": "list",
      "short": "List trackers (tracking links that tie a traffic source to a campaign and landing page)",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Filter by campaign ID (from `p202 campaign list`)",
          "required": false
        },
        {
          "name": "all",
          "type": "bool",
          "default": "false",
          "usage": "Fetch all rows across pages",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Filter by landing page ID (from `p202 landing-page list`)",
          "required": false
        },
        {
          "name": "limit",
          "shorthand": "l",
          "type": "string",
          "default": "",
          "usage": "Max results",
          "required": false
        },
        {
          "name": "offset",
          "shorthand": "o",
          "type": "string",
          "default": "",
          "usage": "Pagination offset",
          "required": false
        },
        {
          "name": "page",
          "type": "string",
          "default": "",
          "usage": "Page number",
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "Filter by PPC account ID (from `p202 ppc-account list`)",
          "required": false
        },
        {
          "name": "resolve-names",
          "type": "bool",
          "default": "false",
          "usage": "Resolve foreign key IDs to names",
          "required": false
        },
        {
          "name": "rotator-id",
          "type": "string",
          "default": "",
          "usage": "Filter by rotator ID (from `p202 rotator list`)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 tracker test",
      "use": "test <tracker_id>",
      "short": "Resolve a tracking link's live destination (follows the redirect)",
      "long": "Fetches the tracker's link and issues a real request per --geo/--device,\nreporting the HTTP status and final destination. Flags a blank/dropped link.",
      "runnable": true,
      "flags": [
        {
          "name": "device",
          "type": "string",
          "default": "",
          "usage": "Device to simulate: desktop, mobile, tablet",
          "allowed_values": [
            "desktop",
            "mobile",
            "tablet"
          ],
          "required": false
        },
        {
          "name": "geo",
          "type": "string",
          "default": "",
          "usage": "Comma-separated country codes to simulate (spoofs X-Forwarded-For)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 tracker update",
      "use": "update <id>",
      "short": "Update a tracker",
      "example": "p202 tracker update <id from p202 tracker list> --aff-campaign-id <new value> --json\n  (only the flags given are sent; the rest of the tracker is unchanged)",
      "runnable": true,
      "flags": [
        {
          "name": "aff-campaign-id",
          "type": "string",
          "default": "",
          "usage": "Campaign ID (from `p202 campaign list`); 0 for a link to a redirector (--rotator-id) or an advanced landing page",
          "required": false
        },
        {
          "name": "click-cloaking",
          "type": "string",
          "default": "",
          "usage": "Cloaking: 1 on, 0 off, -1 use the campaign's setting: -1, 0, 1",
          "allowed_values": [
            "-1",
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "click-cpa",
          "type": "string",
          "default": "",
          "usage": "Cost per action, 0-99.99999; on update, makes the tracker CPA and clears its cost per click. Not with --click-cpc",
          "required": false
        },
        {
          "name": "click-cpc",
          "type": "string",
          "default": "",
          "usage": "Cost per click, 0-99.99999; on update, makes the tracker CPC and clears its cost per action",
          "required": false
        },
        {
          "name": "landing-page-id",
          "type": "string",
          "default": "",
          "usage": "Landing page ID (from `p202 landing-page list`)",
          "required": false
        },
        {
          "name": "ppc-account-id",
          "type": "string",
          "default": "",
          "usage": "PPC account ID (from `p202 ppc-account list`)",
          "required": false
        },
        {
          "name": "rotator-id",
          "type": "string",
          "default": "",
          "usage": "Rotator ID (from `p202 rotator list`)",
          "required": false
        },
        {
          "name": "text-ad-id",
          "type": "string",
          "default": "",
          "usage": "Text ad ID (from `p202 text-ad list`)",
          "required": false
        },
        {
          "name": "tracker-id-public",
          "type": "string",
          "default": "",
          "usage": "Public tracker ID",
          "required": false
        }
      ]
    },
    {
      "path": "p202 user",
      "use": "user",
      "short": "Manage users, roles, API keys, and preferences",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 user apikey",
      "use": "apikey",
      "short": "Manage user API keys",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 user apikey create",
      "use": "create <user_id>",
      "short": "Create an API key for a user",
      "long": "Create an API key. --scope attenuates the key: `read` for a key that can\nnever write (reporting agents), `write` for full read/write, or granular\n`stage` for a propose-only key, or granular `<area>:read`/`<area>:write`/\n`<area>:stage` tokens (comma-separated), e.g.\n`reports:read,forecast-events:read`. Without --scope the key has full\naccess (`*`). A scoped key cannot mint a key broader than itself.",
      "runnable": true,
      "flags": [
        {
          "name": "scope",
          "type": "string",
          "default": "",
          "usage": "Scope for the new key: *, read, write, stage, or comma-separated <area>:read/<area>:write/<area>:stage tokens (`read,stage` is the propose-only agent shape; default: full access)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 user apikey delete",
      "use": "delete <user_id> <api_key>",
      "short": "Delete an API key",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        }
      ]
    },
    {
      "path": "p202 user apikey list",
      "use": "list <user_id>",
      "short": "List API keys for a user",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 user apikey rotate",
      "use": "rotate <user_id> <old_api_key>",
      "short": "Rotate an API key by creating a new one and optionally deleting the old one",
      "runnable": true,
      "flags": [
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt when deleting old key",
          "required": false
        },
        {
          "name": "force-config-update",
          "type": "bool",
          "default": "false",
          "usage": "Update local config even if current key does not match old key",
          "required": false
        },
        {
          "name": "keep-old",
          "type": "bool",
          "default": "false",
          "usage": "Do not delete the old API key",
          "required": false
        },
        {
          "name": "scope",
          "type": "string",
          "default": "",
          "usage": "Scope for the replacement key (default: the old key's scope, carried over)",
          "required": false
        },
        {
          "name": "update-config",
          "type": "bool",
          "default": "false",
          "usage": "Update local ~/.p202/config.json with the new API key",
          "required": false
        }
      ]
    },
    {
      "path": "p202 user create",
      "use": "create",
      "short": "Create a new user",
      "runnable": true,
      "flags": [
        {
          "name": "idempotency-key",
          "type": "string",
          "default": "",
          "usage": "Retry-safe create: the server records the response under this key and replays it on a retry with the same key and payload instead of creating a duplicate",
          "required": false
        },
        {
          "name": "user-active",
          "type": "string",
          "default": "",
          "usage": "1=active (default), 0=inactive: 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "user-email",
          "type": "string",
          "default": "",
          "usage": "Email (required)",
          "required": true
        },
        {
          "name": "user-fname",
          "type": "string",
          "default": "",
          "usage": "First name",
          "required": false
        },
        {
          "name": "user-lname",
          "type": "string",
          "default": "",
          "usage": "Last name",
          "required": false
        },
        {
          "name": "user-name",
          "type": "string",
          "default": "",
          "usage": "Username (required)",
          "required": true
        },
        {
          "name": "user-pass",
          "type": "string",
          "default": "",
          "usage": "Password, 8-72 characters (omit it to be asked without echo, or to pipe it on stdin; a value here stays in shell history)",
          "required": false
        },
        {
          "name": "user-timezone",
          "type": "string",
          "default": "",
          "usage": "Timezone (default: UTC)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 user delete",
      "use": "delete <id>",
      "short": "Delete a user (soft-delete); supports --ids for bulk",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "ids",
          "type": "string",
          "default": "",
          "usage": "Comma-separated user IDs to delete in bulk",
          "required": false
        }
      ]
    },
    {
      "path": "p202 user get",
      "use": "get <id>",
      "short": "Get a user with roles",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 user identity-key",
      "use": "identity-key",
      "short": "Show or rotate the key your server signs customer ids with",
      "long": "The identity linking key is what your own server signs customer ids with, so a\n`cust` on a public pixel or tracking link joins a person's journeys only when it\ncarries `cust_sig`:\n\n  cust_sig = hex(HMAC-SHA256(linking_key, \"<cust_type>:<cust>\"))\n\ncust_type defaults to custom; email_md5/email_sha256 digests are signed in lower case.",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 user identity-key get",
      "use": "get <user_id>",
      "short": "Show the identity linking key (minted on first use)",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 user identity-key rotate",
      "use": "rotate <user_id>",
      "short": "Replace the identity linking key; signatures made with the old key stop linking",
      "runnable": true,
      "flags": [
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        }
      ]
    },
    {
      "path": "p202 user list",
      "use": "list",
      "short": "List all users",
      "runnable": true,
      "flags": [],
      "tasks": [
        {
          "run": "p202 user list",
          "ui_pages": [
            "User Management"
          ],
          "phrases": [
            "team members"
          ]
        }
      ]
    },
    {
      "path": "p202 user prefs",
      "use": "prefs",
      "short": "Manage user preferences",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 user prefs get",
      "use": "get <user_id>",
      "short": "Get user preferences",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 user prefs update",
      "use": "update <user_id>",
      "short": "Update user preferences (profile, report defaults, integration keys, LTV settings)",
      "long": "Sets the preferences the settings pages set: Personal settings (time zone is on `user update`), the report\ndefaults, Integrations' network keys and LTV › Settings. Each value is checked against the page's own choices\nbefore any request; a free-text value given as \"\" clears it. Changing --user-account-currency re-prices every\ncampaign's payout into the new currency, as Personal settings does, through the exchange-rate service.",
      "example": "p202 user prefs update 1 --user-daily-email 07 --user-pref-time-predefined last7\n  p202 user prefs update 1 --user-tracking-domain \"\"     # back to this install's own domain\n  p202 user prefs update 1 --user-account-currency EUR",
      "runnable": true,
      "flags": [
        {
          "name": "cb-key",
          "type": "string",
          "default": "",
          "usage": "ClickBank secret key; changing it resets its verification (\"\" removes it)",
          "required": false
        },
        {
          "name": "chart-time-range",
          "type": "string",
          "default": "",
          "usage": "Overview chart resolution: hours, days",
          "allowed_values": [
            "hours",
            "days"
          ],
          "required": false
        },
        {
          "name": "ipqs-api-key",
          "type": "string",
          "default": "",
          "usage": "IPQualityScore API key (\"\" removes it)",
          "required": false
        },
        {
          "name": "jvzoo-ipn-secret-key",
          "type": "string",
          "default": "",
          "usage": "JVZoo IPN secret key (\"\" removes it)",
          "required": false
        },
        {
          "name": "user-account-currency",
          "type": "string",
          "default": "",
          "usage": "Account currency; re-prices every campaign's payout into it: AUD, BRL, CAD, CHF, CNY, CZK, DKK, EUR, GBP, HKD, HUF, ILS, INR, JPY, MXN, MYR, NOK, NZD, PHP, PLN, RUB, SEK, SGD, THB, TRY, TWD, USD",
          "allowed_values": [
            "AUD",
            "BRL",
            "CAD",
            "CHF",
            "CNY",
            "CZK",
            "DKK",
            "EUR",
            "GBP",
            "HKD",
            "HUF",
            "ILS",
            "INR",
            "JPY",
            "MXN",
            "MYR",
            "NOK",
            "NZD",
            "PHP",
            "PLN",
            "RUB",
            "SEK",
            "SGD",
            "THB",
            "TRY",
            "TWD",
            "USD"
          ],
          "required": false
        },
        {
          "name": "user-cpc-or-cpv",
          "type": "string",
          "default": "",
          "usage": "Show costs per click (cpc) or per view (cpv, 5 decimals): cpc, cpv",
          "allowed_values": [
            "cpc",
            "cpv"
          ],
          "required": false
        },
        {
          "name": "user-daily-email",
          "type": "string",
          "default": "",
          "usage": "Hour the daily stats email is sent, in your time zone: never, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23",
          "allowed_values": [
            "never",
            "00",
            "01",
            "02",
            "03",
            "04",
            "05",
            "06",
            "07",
            "08",
            "09",
            "10",
            "11",
            "12",
            "13",
            "14",
            "15",
            "16",
            "17",
            "18",
            "19",
            "20",
            "21",
            "22",
            "23"
          ],
          "required": false
        },
        {
          "name": "user-keyword-searched-or-bidded",
          "type": "string",
          "default": "",
          "usage": "Keyword to record: the one searched or the one bid on: searched, bidded",
          "allowed_values": [
            "searched",
            "bidded"
          ],
          "required": false
        },
        {
          "name": "user-ltv-customer-cparam",
          "type": "string",
          "default": "",
          "usage": "Tracking variable that carries a customer id: 0 off, 1-4 for c1-c4: 0, 1, 2, 3, 4",
          "allowed_values": [
            "0",
            "1",
            "2",
            "3",
            "4"
          ],
          "required": false
        },
        {
          "name": "user-ltv-personalization-fields",
          "type": "string",
          "default": "",
          "usage": "Fields a landing page may personalize with: comma list of first_name, last_name, company, city, country, cf:<field_key>, rec:next_offer (\"\" none)",
          "required": false
        },
        {
          "name": "user-ltv-rec-fatigue",
          "type": "string",
          "default": "",
          "usage": "Next-offer fatigue: times,days such as 3,21; 0 turns it off (\"\" the defaults)",
          "required": false
        },
        {
          "name": "user-ltv-score-weights",
          "type": "string",
          "default": "",
          "usage": "Engagement score weights, volume:N,time:N,scroll:N,video:N,recency:N summing to 100 (\"\" the defaults 40/20/15/15/10)",
          "required": false
        },
        {
          "name": "user-pref-ad-settings",
          "type": "string",
          "default": "",
          "usage": "Where Prosper202 shows its ads: show_all, hide_login, hide_all",
          "allowed_values": [
            "show_all",
            "hide_login",
            "hide_all"
          ],
          "required": false
        },
        {
          "name": "user-pref-cloak-referer",
          "type": "string",
          "default": "",
          "usage": "What a cloaked link shows as referer: origin (this domain) or never (blank): origin, never",
          "allowed_values": [
            "origin",
            "never"
          ],
          "required": false
        },
        {
          "name": "user-pref-dynamic-bid",
          "type": "string",
          "default": "",
          "usage": "Click cost: 0 from the tracker's setup, 1 from the t202b link parameter: 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "user-pref-limit",
          "type": "string",
          "default": "",
          "usage": "Default rows per report page: 10, 25, 50, 75, 100, 150, 200",
          "allowed_values": [
            "10",
            "25",
            "50",
            "75",
            "100",
            "150",
            "200"
          ],
          "required": false
        },
        {
          "name": "user-pref-privacy",
          "type": "string",
          "default": "",
          "usage": "Privacy mode: disabled, eu (European traffic only) or all traffic: disabled, eu, all",
          "allowed_values": [
            "disabled",
            "eu",
            "all"
          ],
          "required": false
        },
        {
          "name": "user-pref-referer-data",
          "type": "string",
          "default": "",
          "usage": "Referer to record: the browser's, or the t202ref link parameter: browser, t202ref",
          "allowed_values": [
            "browser",
            "t202ref"
          ],
          "required": false
        },
        {
          "name": "user-pref-time-predefined",
          "type": "string",
          "default": "",
          "usage": "Default report date range: today, yesterday, last7, last14, last30, thismonth, lastmonth, thisyear, lastyear, alltime",
          "allowed_values": [
            "today",
            "yesterday",
            "last7",
            "last14",
            "last30",
            "thismonth",
            "lastmonth",
            "thisyear",
            "lastyear",
            "alltime"
          ],
          "required": false
        },
        {
          "name": "user-slack-incoming-webhook",
          "type": "string",
          "default": "",
          "usage": "Slack incoming webhook URL, https:// (\"\" stops Slack notifications)",
          "required": false
        },
        {
          "name": "user-tracking-domain",
          "type": "string",
          "default": "",
          "usage": "Domain tracking links are built on, e.g. track.example.com (\"\" uses this install's own)",
          "required": false
        },
        {
          "name": "zaxaa-api-signature",
          "type": "string",
          "default": "",
          "usage": "Zaxaa API signature (\"\" removes it)",
          "required": false
        }
      ],
      "tasks": [
        {
          "run": "p202 user prefs update",
          "ui_pages": [
            "Personal Settings"
          ],
          "phrases": [
            "my preferences",
            "report defaults",
            "privacy setting"
          ]
        }
      ]
    },
    {
      "path": "p202 user role",
      "use": "role",
      "short": "Manage user roles",
      "runnable": false,
      "flags": []
    },
    {
      "path": "p202 user role assign",
      "use": "assign <user_id> <role_id>",
      "short": "Assign a role to a user",
      "runnable": true,
      "flags": [
        {
          "name": "role-id",
          "type": "string",
          "default": "",
          "usage": "Role ID (alternative to the second positional arg)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 user role list",
      "use": "list",
      "short": "List all available roles",
      "runnable": true,
      "flags": []
    },
    {
      "path": "p202 user role remove",
      "use": "remove <user_id> <role_id>",
      "short": "Remove a role from a user",
      "runnable": true,
      "flags": [
        {
          "name": "dry-run",
          "type": "bool",
          "default": "false",
          "usage": "Preview what the delete would remove (record + cascade counts) without deleting",
          "required": false
        },
        {
          "name": "force",
          "shorthand": "f",
          "type": "bool",
          "default": "false",
          "usage": "Skip confirmation prompt",
          "required": false
        },
        {
          "name": "role-id",
          "type": "string",
          "default": "",
          "usage": "Role ID (alternative to the second positional arg)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 user update",
      "use": "update <id>",
      "short": "Update a user: rename, name, email, timezone, active, password",
      "runnable": true,
      "flags": [
        {
          "name": "current-password",
          "type": "bool",
          "default": "false",
          "usage": "Send your current password, which changing your OWN password needs (asked without echo, or the first line of piped stdin)",
          "required": false
        },
        {
          "name": "set-password",
          "type": "bool",
          "default": "false",
          "usage": "Set a new password, read without echo: asked twice at a terminal, or one line of piped stdin",
          "required": false
        },
        {
          "name": "user-active",
          "type": "string",
          "default": "",
          "usage": "1=active, 0=inactive: 0, 1",
          "allowed_values": [
            "0",
            "1"
          ],
          "required": false
        },
        {
          "name": "user-email",
          "type": "string",
          "default": "",
          "usage": "Email",
          "required": false
        },
        {
          "name": "user-fname",
          "type": "string",
          "default": "",
          "usage": "First name",
          "required": false
        },
        {
          "name": "user-lname",
          "type": "string",
          "default": "",
          "usage": "Last name",
          "required": false
        },
        {
          "name": "user-name",
          "type": "string",
          "default": "",
          "usage": "New username (the sign-in name): renames the account, as the Users page does; needs a user you may manage, even yourself",
          "required": false
        },
        {
          "name": "user-pass",
          "type": "string",
          "default": "",
          "usage": "New password, 8-72 characters (prefer --set-password: a value here stays in shell history)",
          "required": false
        },
        {
          "name": "user-timezone",
          "type": "string",
          "default": "",
          "usage": "Time zone, e.g. America/New_York (a PHP time zone name)",
          "required": false
        }
      ]
    },
    {
      "path": "p202 whoami",
      "use": "whoami",
      "short": "Show the user, roles and scopes the configured API key acts as",
      "long": "Asks the server who the configured key belongs to: its user id and username, the\nuser's roles, and the key's scopes (`*` is full access; `read`, `campaigns:write`\nand the like narrow it). Fails with exit 2 when the server refuses the key.\n\n  p202 whoami\n  p202 whoami --profile staging --json",
      "runnable": true,
      "flags": []
    }
  ],
  "not_in_cli": [
    {
      "ui_pages": [
        "Home"
      ],
      "instead": "the account home is a get-started checklist",
      "hint": "Its steps are `p202 ppc-network create` and `p202 ppc-account create`, `p202 campaign create`, then `p202 tracker create-with-url`."
    },
    {
      "ui_pages": [
        "Watch TV202"
      ],
      "phrases": [
        "tv202"
      ],
      "instead": "it plays Tracking202's hosted videos",
      "hint": "Open the page in the web UI."
    },
    {
      "ui_pages": [
        "Hot Deals & Discounts"
      ],
      "phrases": [
        "hot deals"
      ],
      "instead": "it lists Tracking202's hosted offers",
      "hint": "Open the page in the web UI."
    },
    {
      "ui_pages": [
        "VIP Perks Profile"
      ],
      "instead": "it is your profile on Tracking202's hosted service",
      "hint": "Open the page in the web UI."
    },
    {
      "ui_pages": [
        "Help"
      ],
      "instead": "it links the documentation and support",
      "hint": "`p202 --help`, `p202 <command> --help` and `p202 commands` describe the CLI."
    },
    {
      "phrases": [
        "upgrade",
        "1-click upgrade",
        "upgrade prosper202",
        "install upgrade"
      ],
      "instead": "upgrades run from the web UI's upgrade page",
      "hint": "`p202 system info` says which version is installed and whether an upgrade is needed."
    }
  ]
}
