p202 campaign replace-url

Find campaigns whose offer URLs contain a string and rewrite those URLs in bulk

Writessupports --staged
All commands

01Run it

Straight from the command's own help.

p202 campaign replace-url --match g2afse.com --set 'https://example.com/?utm_source={slug}' --dry-run
p202 campaign replace-url --match http://promo.example.com --with https://promo.example.com --force
p202 campaign replace-url --undo ~/.p202/undo/replace-url-20260930T101500Z.json --dry-run

02What you get

Pick the shape you need. People get a table. Add --json, --csv or --ndjson for scripts, or -q for ids only. An AI agent gets compact JSON without asking. All output formats

03Build your command

Pick values and the command line writes itself, quoted and ready to paste.

p202 campaign replace-url

Set flags below; the command updates as you type.

04Flags

9 flags, plus the global flags every command takes.

FlagWhat it does
--aff-network-idstringOnly campaigns in this affiliate network (p202 aff-network list)
--dry-runboolList the changes without writing anything
--force, -fboolSkip the confirmation prompt
--idsstringOnly these campaign IDs (comma-separated)
--matchstringText the offer URLs to change contain (case-insensitive; required unless --undo)
--setstringReplace the whole URL with this; {id} and {slug} are filled per campaign
--slotstring ยท default allURL slots to consider: 1-5, comma-separated, or all
--undostringRevert a run from its undo manifest file (printed after "Undo with:"): restores old URLs where the slot is unchanged since
--withstringReplace the matched text with this

05How it works

Finds every campaign whose offer URL slots (aff_campaign_url, _2 to _5) contain --match (case-insensitive), and rewrites the matching slots:

--with <text> replaces the matched text inside the URL --set <url> replaces the whole URL; {id} and {slug} (the campaign name, lowercased and hyphenated) are filled per campaign

Run with --dry-run first: it lists every campaign, slot, old and new URL and writes nothing. Without --dry-run the same list is shown and you are asked to confirm (--force skips the prompt; --staged records one proposal per campaign instead of writing). Matching runs in the CLI over every page of campaigns, so it works against any server version.

Re-running is safe with --set (updated URLs no longer contain --match), but with --with it rewrites again if the replacement still contains --match.

Undo: every run that applies a change saves the applied slots (old and new URL, profile, base URL) to ~/.p202/undo/replace-url-<UTC time>.json and prints Undo with: p202 campaign replace-url --undo <file> (under --json also meta.undo_manifest). --undo puts old_url back only where the slot still holds that run's new_url; slots changed since, and deleted campaigns, are left alone and listed with status skipped. It refuses a manifest written against another base URL, cannot be combined with --match, --with, --set, --slot, --ids or --aff-network-id, and otherwise behaves like a normal run (--dry-run, the prompt, --force, --staged, exit 5 on a failed PUT). An undo that applies changes saves its own manifest, so it can be undone too. If a manifest cannot be saved after the writes, the command prints it on stderr and exits 5.

06For agents

Running this from an agent

  • Read the same facts as JSON: p202 commands campaign replace-url --json.
  • With AI_AGENT, CLAUDECODE or another agent variable set, output is compact JSON and errors arrive on stderr as a JSON envelope with a hint.
  • Exit codes: 0 ok, 1 bad input, 2 auth, 3 network, 4 server error, 5 partial failure.
  • This command writes. Add --staged to record it as a proposal a person applies with p202 change apply.
p202 commands campaign replace-url --json
{
  "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.",
  "runnable": true,
  "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",
  "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
    }
  ]
}