From ae5ffa2f62664fe30013c0a1bafd6519dba9424b Mon Sep 17 00:00:00 2001 From: sonpiaz Date: Mon, 12 Oct 2026 23:35:11 -0700 Subject: [PATCH] fix: CLI and verification docs match the code No Run verification button exists; affitor setup stripe cannot connect Stripe (dashboard only); onboard and whoami --json exit 1 on a negative outcome; program keys start with aff_. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../docs/api-reference/agent-integration.mdx | 7 +-- content/docs/brand/cli/commands.mdx | 59 ++++--------------- content/docs/brand/cli/quickstart.mdx | 15 +---- .../brand/quickstart/define-commission.mdx | 2 +- content/docs/brand/quickstart/payouts.mdx | 2 +- .../brand/tracking/quickstart-integration.mdx | 4 +- .../brand/tracking/testing-integration.mdx | 13 ++-- 7 files changed, 29 insertions(+), 73 deletions(-) diff --git a/content/docs/api-reference/agent-integration.mdx b/content/docs/api-reference/agent-integration.mdx index 7a779bb6..f74b2fc6 100644 --- a/content/docs/api-reference/agent-integration.mdx +++ b/content/docs/api-reference/agent-integration.mdx @@ -82,11 +82,11 @@ curl -X POST https://api.affitor.com/api/v1/track/lead \ -d '{"customer_key": "user_123", "email": "user@example.com"}' ``` -**3. Sale tracking** — three options in priority order: Stripe OAuth auto-connect, Server-side tracking vs Stripe integration: +**3. Sale tracking**: Stripe connected in the dashboard, or server-side tracking: ```bash -# Option A: auto-connect Stripe (recommended) -npx affitor setup stripe +# Option A: Stripe (recommended). Connect it in the Affitor dashboard (program Settings, Connect Stripe) +# and add Affitor metadata to your Checkout Session. The CLI does not connect Stripe. # Option B: Server-side tracking — your backend calls POST /api/v1/track/sale (any payment provider) curl -X POST https://api.affitor.com/api/v1/track/sale \ @@ -124,7 +124,6 @@ The file includes a table that tells agents which field name to use in each cont ```bash npx affitor status # Check program health -npx affitor setup stripe # Auto-connect Stripe via OAuth npx affitor test click # Send test click event npx affitor test lead # Send test lead event npx affitor test sale # Send test sale event diff --git a/content/docs/brand/cli/commands.mdx b/content/docs/brand/cli/commands.mdx index ff477056..69b15f9f 100644 --- a/content/docs/brand/cli/commands.mdx +++ b/content/docs/brand/cli/commands.mdx @@ -30,7 +30,7 @@ Two different credentials are in play, and they are not interchangeable. | Credential | Where it lives | Which commands use it | |---|---|---| | Account session | `~/.affitor/credentials.json`, written by `affitor login` | `affitor init`, `affitor programs`, `affitor whoami` | -| Program API key | `AFFITOR_API_KEY` in the environment or `.affitor/.env`, or `--api-key` | `affitor onboard`, `affitor status`, `affitor test`, `affitor setup stripe` | +| Program API key | `AFFITOR_API_KEY` in the environment or `.affitor/.env`, or `--api-key` | `affitor onboard`, `affitor status`, `affitor test` | Run `affitor login` before the first group. Without a session, `init` and `programs` stop and exit non-zero (`not_logged_in` in `--json` mode) — they never fall back to a program API key. @@ -70,7 +70,7 @@ Show which account the stored session belongs to, and when its token expires. npx affitor whoami ``` -With no session it exits non-zero. `whoami --json` instead prints `{"logged_in": false}` and exits `0`, so a script should read that field rather than the exit code. +With no session it exits non-zero. `whoami --json` prints `{"logged_in": false}` and also exits `1`. --- @@ -182,7 +182,7 @@ In `--json` mode `onboard` performs **no file edits** — the steps that would h ### Example (agent / non-interactive) ```bash -npx affitor onboard --api-key affitor_xxx --yes --json +npx affitor onboard --api-key aff_xxx --yes --json ``` The JSON summary reports the per-step status and the final verdict: @@ -204,7 +204,7 @@ The JSON summary reports the per-step status and the final verdict: Once `onboard` reaches the verification phase, `--json` always prints this summary. `program_id`, `steps` and `integration_verified` are always present, though `program_id` is `null` when no readiness verdict was obtained. `blocker`, `next_action` and `error` are omitted rather than sent as null, so read them with that in mind. -The only way to get no summary is for `onboard` to stop before it runs: with no API key it prints `{"error": "no_api_key"}` and exits non-zero. +The only way to get no summary is for `onboard` to stop before it runs: with no API key it prints `{"error": "no_api_key"}` and exits non-zero. `onboard` exits `0` only when `integration_verified` is `true`; otherwise it prints the summary and exits `1`. **What `integration_verified: false` means.** The verification chain and the readiness poll are separate: if the chain fails to run, `onboard` carries on polling anyway, so a chain failure never decides the verdict. Readiness does. Three cases produce `false`, and the other fields tell them apart: @@ -220,45 +220,13 @@ A readiness poll that succeeds after a failed chain still reports `integration_v ## `affitor setup stripe` -Connect your Stripe account so payments are tracked automatically. +Stripe is connected from the Affitor dashboard, not from the CLI: open the program, go to **Settings**, and use **Connect Stripe**. Affitor's own webhook then records sales, renewals and refunds for that account; nothing needs to be created on your Stripe account. To attribute each sale, add Affitor metadata to your Checkout Session, as described in the [Stripe integration guide](/docs/api-reference/integrations/stripe). ```bash npx affitor setup stripe ``` -**What happens:** - -1. Opens Stripe Connect OAuth in your browser -2. You authorize Affitor to read your payment data -3. A webhook endpoint is created on your Stripe account -4. Connection is saved to your program config - -| Flag | Description | -|---|---| -| `--stripe-client-id ` | Override Stripe Connect client ID | -| `--stripe-secret-key ` | Override Stripe secret key | - -**Environment variables (alternative to flags):** - -- `STRIPE_CONNECT_CLIENT_ID` or `AFFITOR_STRIPE_CLIENT_ID` -- `STRIPE_SECRET_KEY` or `AFFITOR_STRIPE_SECRET_KEY` - -**Webhook events subscribed:** - -```text -customer.created -checkout.session.completed -invoice.paid -invoice.payment_failed -charge.refunded -customer.subscription.deleted -``` - -The endpoint is created on your connected Stripe account with the delivery URL `/webhooks/stripe/` — for the default API URL, `https://api.affitor.com/webhooks/stripe/430`. That is the URL this command sends to Stripe; it is the value to check in the Stripe dashboard if deliveries are not arriving. - - - After running this command, send a test event from the Stripe dashboard and confirm the sale shows up in Affitor before you treat Stripe tracking as live. If nothing arrives, report the sale from your own backend instead — see [Track Sale](/docs/api-reference/track-sale) or the [Stripe integration guide](/docs/api-reference/integrations/stripe), which does not depend on this endpoint. - +From CLI 0.4.3 this command only prints those directions and exits `1` (`{"error": "stripe_setup_moved", "message": "..."}` with `--json`). Earlier versions start a browser flow that cannot complete; do not use it. --- @@ -343,13 +311,11 @@ Secrets (the program API key, and provider webhook secrets) are **not** stored i ## When a command fails -A command that cannot do its job exits non-zero. Three outcomes are the exception, because they are results rather than failures, and each one is reported in the output instead: +A command that cannot do its job exits non-zero. Since CLI 0.4.2 that includes `affitor onboard` when the integration is not verified (`integration_verified: false`) and `affitor whoami --json` when no session is stored; both still print their JSON first. One outcome is the exception, because it is a result rather than a failure, and it is reported in the output instead: | Command | Reports a negative outcome with exit `0` | Read instead | |---|---|---| -| `affitor onboard` | Verification did not pass | `integration_verified` in the summary | | `affitor test` | The test event was not received | `received` in the JSON result | -| `affitor whoami --json` | No session is stored | `logged_in` | ### What `--json` puts on `error` @@ -359,7 +325,7 @@ A command that cannot do its job exits non-zero. Three outcomes are the exceptio |---|---|---| | A machine code | Every check a command makes before it calls the API | `{"error": "not_logged_in"}` | | The API's message, with the HTTP status beside it | `init`, `status`, `test` when the API rejects the call | `{"error": "Invalid API token", "status": 401}` | -| A code with the message in its own field | `setup stripe` | `{"error": "api_error", "message": "..."}` | +| A code with the message in its own field | `setup stripe` | `{"error": "stripe_setup_moved", "message": "..."}` | `onboard` is different again. Once it gets past its own preflight checks it prints a summary object, and in that summary `error` is itself an **object** rather than a string — the one place the CLI hands you the API's own error code: @@ -384,17 +350,16 @@ Two gaps are worth knowing before you build on this output: | Condition | `--json` code | Commands | What to do | |---|---|---|---| | Not logged in | `not_logged_in` | `init`, `programs` | Run `affitor login`, then re-run the command | -| No config in this directory | `no_config` | `status`, `test`, `setup` | Run the command from the project root where you ran `affitor init`, or run `affitor init` to create a program here | +| No config in this directory | `no_config` | `status`, `test`, `setup dns` | Run the command from the project root where you ran `affitor init`, or run `affitor init` to create a program here | | Already configured | `already_configured` | `init` | `init` found an existing `.affitor/config.json` and changed nothing. Use `affitor status` to check that program. Do not run `init` to recover a key — it only ever creates a new program | | Missing required options | `missing_options` | `init` with `--no-interactive` | Pass `--name`, `--domain`, `--commission-type` and `--commission-rate` | | Invalid event type | `invalid_event_type` | `test` | `affitor test` takes `click`, `lead`, or `sale` | | No API key | `no_api_key` | `onboard` | Pass `--api-key`, set `AFFITOR_API_KEY`, or run from a directory with `.affitor/.env` | | API rejected the call, account session | `error` is the API message, `status` the HTTP status | `init` | `init` authenticates with your account session, not a program key. A `401` here means the session is invalid or expired — run `affitor login` again. Do **not** regenerate a program key for this: it will not fix the session, and it breaks whatever is still using the old key | | API rejected the call, program key | `error` is the API message, `status` the HTTP status | `status`, `test` | On a `401`, the key matches no program or was replaced. Compare it against the value you stored when it was issued; if you no longer hold that value, ask a workspace owner to regenerate the key under Settings → API Key and deploy the new one | -| API rejected the call | `api_error`, with the API message on `message` and no `status` | `setup stripe` | Read `message`. A `401` here is a program-key problem, as in the row above | -| Stripe authorization failed | `stripe_oauth_error` | `setup stripe` | Read `message`, then run `affitor setup stripe` again | -| No usable response | `network_error` | `init`, `status`, `test`, `setup stripe` | See below | -| Anything else | `unexpected_error` | `init`, `status`, `test`, `setup stripe` | Re-run with `--verbose` and keep the output | +| Stripe is connected elsewhere | `stripe_setup_moved` | `setup stripe` | Connect Stripe in the dashboard: program **Settings**, **Connect Stripe** | +| No usable response | `network_error` | `init`, `status`, `test` | See below | +| Anything else | `unexpected_error` | `init`, `status`, `test` | Re-run with `--verbose` and keep the output | ### `network_error` does not mean the request was ignored diff --git a/content/docs/brand/cli/quickstart.mdx b/content/docs/brand/cli/quickstart.mdx index a9311115..9b419185 100644 --- a/content/docs/brand/cli/quickstart.mdx +++ b/content/docs/brand/cli/quickstart.mdx @@ -96,18 +96,7 @@ Choose your payment tracking method: **Server-side tracking vs Stripe integratio ### Option A: Stripe integration (automatic) -Auto-configure Stripe webhooks for payment tracking: - -```bash -npx affitor setup stripe -``` - -This opens Stripe Connect OAuth in your browser, then automatically creates webhook endpoints for: -- `checkout.session.completed` -- sale tracking -- `invoice.payment_succeeded` -- recurring commission -- `charge.refunded` -- automatic commission clawback -- `customer.created` -- lead tracking -- `customer.subscription.deleted` -- churn tracking +Connect Stripe in the Affitor dashboard: open the program, go to **Settings**, and use **Connect Stripe**. Affitor's own webhook then records sales, renewals and refunds. Add Affitor metadata to your Checkout Session so each sale is attributed; see the [Stripe integration guide](/docs/api-reference/integrations/stripe). The CLI does not connect Stripe (`affitor setup stripe` only points you to the dashboard). ### Option B: Server-side tracking — your backend calls POST /api/v1/track/sale (any payment provider) @@ -161,7 +150,7 @@ Output is valid JSON, ready for AI agents to parse: ```json { "program_id": 430, - "api_key": "affitor_...", + "api_key": "aff_...", "domain": "example.com", "status": "created", "tracking": { diff --git a/content/docs/brand/quickstart/define-commission.mdx b/content/docs/brand/quickstart/define-commission.mdx index 389fd802..3e1a77cf 100644 --- a/content/docs/brand/quickstart/define-commission.mdx +++ b/content/docs/brand/quickstart/define-commission.mdx @@ -152,7 +152,7 @@ Use [partner groups](/docs/brand/groups) to give different partner segments diff ## Verify it worked diff --git a/content/docs/brand/quickstart/payouts.mdx b/content/docs/brand/quickstart/payouts.mdx index 942437f4..bd4382b3 100644 --- a/content/docs/brand/quickstart/payouts.mdx +++ b/content/docs/brand/quickstart/payouts.mdx @@ -87,7 +87,7 @@ Partners manage their payout details inside the payout workflow; advertisers do ## Verify it worked diff --git a/content/docs/brand/tracking/quickstart-integration.mdx b/content/docs/brand/tracking/quickstart-integration.mdx index de6fe913..2bc49860 100644 --- a/content/docs/brand/tracking/quickstart-integration.mdx +++ b/content/docs/brand/tracking/quickstart-integration.mdx @@ -30,9 +30,9 @@ Use one naming scheme consistently: Add the tracker to every page where affiliate traffic can land. -:::tip[Verifying is one click] +:::tip[Verifying the pipeline] -Once the tracker is live on your public site, Affitor detects it automatically — no debug mode needed. To verify the full pipeline, use the **Run verification** button on the Share Program step (it runs a synthetic `click → signup → sale`). See [Testing Integration](/docs/brand/tracking/testing-integration). +Once the tracker is live on your public site, Affitor detects it automatically, with no debug mode needed. To verify the full pipeline, run the synthetic `click → signup → sale` chain with `npx affitor onboard` or the MCP `affitor_run_verification` tool. See [Testing Integration](/docs/brand/tracking/testing-integration). ::: diff --git a/content/docs/brand/tracking/testing-integration.mdx b/content/docs/brand/tracking/testing-integration.mdx index 2e9dea94..7cd93466 100644 --- a/content/docs/brand/tracking/testing-integration.mdx +++ b/content/docs/brand/tracking/testing-integration.mdx @@ -11,17 +11,20 @@ Before going live, verify each layer in order to confirm that your identifiers, --- -## The easy way — Run verification +## The synthetic verification chain -You don't need to manually test each layer. Once your tracking code is live on your **public site**, Affitor **detects it automatically** (no debug mode required), and on the **Share Program** step the dashboard shows a **Run verification** button. +Once your tracking code is live on your **public site**, Affitor **detects it automatically** (no debug mode required). The dashboard has no verification button: **Go Live** on the **Share Program** step publishes the program once its profile and commission are set, and it does not test your integration. -**Run verification** fires a synthetic `click → signup → sale` through Affitor's real attribution + commission pipeline — no real customer, no real money — and shows you a per-step verdict. When the synthetic **sale** is attributed, your integration is verified and **Go Live** unlocks. +To check the whole pipeline without a real customer, run the synthetic `click → signup → sale` chain through Affitor's real attribution and commission pipeline, with no real money. Two ways run it: -This is the same check the agent runs with `affitor test` (and the MCP `affitor_run_verification` tool), so humans and agents verify the exact same way. +- `npx affitor onboard`, which fires the chain and then polls readiness until `integration_verified` is reached (see [CLI commands](/docs/brand/cli/commands)) +- the MCP `affitor_run_verification` tool, followed by `affitor_readiness` + +`affitor test click|lead|sale` sends one test event at a time; it does not run the chain. :::tip -Run verification needs an **active commission policy** (so the synthetic sale can produce a commission). Set your commission first, then run it. Limited to 10 runs/hour. +The chain needs an **active commission policy** (so the synthetic sale can produce a commission). Set your commission first, then run it. Limited to 10 runs per program per hour. :::