p202 conversion import

Record a network's conversion export (CSV or JSON) against its clicks, safely re-runnable

Writessupports --staged
All commands

01Run it

Straight from the command's own help.

p202 conversion import a2hosting-feb.csv --dry-run
p202 conversion import a2hosting-feb.csv --dry-run --check-clicks
p202 conversion import export.csv --subid-column 'Sub ID 2' --time-column 'Sale Date' --timezone America/New_York
p202 conversion import conversions.json --force --json

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 conversion import

Set flags below; the command updates as you type.

04Flags

9 flags, plus the global flags every command takes.

FlagWhat it does
--check-clicksboolWith --dry-run, also read each click's conversions to show click_not_found and duplicate rows
--dry-runboolShow the plan and write nothing (no request unless --check-clicks)
--force, -fboolSkip the confirmation prompt
--payout-columnstringHeader of the payout column (default: auto-detect; with no payout column the campaign's default payout applies)
--subid-columnstringHeader of the column holding the Prosper202 subid (default: auto-detect)
--time-columnstringHeader of the conversion time column (default: auto-detect; with no time column the server records now)
--time-formatstringGo time layout of the time column, e.g. '01/02/2006 15:04' (default: unix or ISO dates)
--timezonestring · default UTCZone of times written without one: UTC, an IANA name, or an offset like -05:00
--txid-columnstringHeader of the transaction id column (default: auto-detect)

05How it works

Reads a network's conversion export — a CSV file with a header row, or a JSON array of objects — and records each line as a conversion on the click its subid names.

Columns (auto-detected from the header, case and punctuation ignored; the flags override): subid required: subid, sub_id, aff_sub, sub1, click_id, clickid, s2 (--subid-column) payout optional: payout, commission, amount, revenue (--payout-column); $ and thousands separators (1,234.50) are dropped, a decimal comma (12,50) is refused; absent = the campaign's default payout transaction id optional: transaction_id, order_id, txid (--txid-column) time optional: date, time, conversion_date, created_at (--time-column); unix seconds or ms, or 2026-02-03[ 14:05[:00]] in --timezone (default UTC), RFC 3339, or any Go layout given with --time-format; absent = now More than one candidate header for a column is refused: name the one to use.

The subid is read as the postback (gpb.php) reads it: the click id, digits only, no leading zero. Rows are marked invalid (with the reason) or duplicate_in_file (the same click and transaction id as an earlier row; without a transaction id a click converts once, as the postback does). A negative payout with a transaction id reverses that sale; negative rows are sent after the sales, so a newest-first report reverses the right one.

--dry-run shows that plan without contacting the server; add --check-clicks to also read each click's conversions (GET /clicks/{id}/conversions, read-only, once per click). Without --dry-run the clicks are always read first, then you confirm (--force skips; --staged records proposals instead), then each ready row is sent as POST /conversions with an Idempotency-Key derived from its click, transaction id, payout and time.

Statuses: created, duplicate (the click already has it: same transaction id, or any conversion for an id-less row, or the key was replayed, or the server answered it as a duplicate or as a deleted conversion's transaction id), conflict (the click has the transaction id with another payout or time; not sent), click_not_found, failed (with the server's message), staged, invalid, duplicate_in_file (ready in a dry run). Re-running the same file is safe: recorded rows come back as duplicate. Exit 5 if any row failed or conflicts; re-running the same command then sends only the rows not yet recorded.

06For agents

Running this from an agent

  • Read the same facts as JSON: p202 commands conversion import --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 conversion import --json
{
  "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.",
  "runnable": true,
  "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",
  "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
    }
  ]
}