Uh oh!
There was an error while loading. Please reload this page.
158909 :: docs: AutoPay public documentation - #169
Conversation
…enshots Lane-0 scaffold so #158910 and #158912 can be written in parallel without both editing sidebars.ts. - developerSidebar: AutoPay Pattern-A anchor category after M-Wallet - businessSidebar: AutoPay Pattern-A anchor category after M-Wallet - skeleton pages pinning every heading id the sidebar links to - 22 customer-portal and notification screenshots from Menna (real PNGs, largest 154 KB, wallet naming convention, no stubs) Merchant-side screens are deliberately absent: AutoPay is REST-API-only on the merchant side in this phase (confirmed by Dacian, 2026-08-13). Refs #158909 #158910 #158912 #158913
Mirrors the M-Wallet pair the epic names as the reference model. The plan carries a verified-facts ledger with a source citation for every behavioural claim, plus six findings that appear in no ticket: - the autopay request block is write-only, not echoed in the 201 - customer_email is required; omitting it surfaces as a misleading 400 - page-link does not rotate the token; regenerate-page-token revokes - the customer page is served from the Connect host, language in the path - the page token is signed, not encrypted — payload is readable base64 - the nonce is what makes revocation work at all Refs #158909 #158910 #158912 #158915
New page at /developers/payments/autopay/ following the M-Wallet shape and the section order mandated by docs/developers/CLAUDE.md. - AutoPayFlowDiagram.tsx — inline theme-aware SVG, matching WalletFlowDiagram and RecurringFlow; not Mermaid - payments/index.md — AutoPay card and Choose Your Path row - glossary-terms.ts — subscription, billing cycle, dunning - recurring-payments.mdx — reverse half of the deconfliction cross-link, so a reader who lands on auto_debit expecting subscriptions is redirected ## API Reference is intentionally a placeholder: core_backend PR 121 has not merged, so the public OpenAPI schema serves no AutoPay endpoints and <ApiDocEmbed> cannot resolve. The six endpoints are documented as prose and cURL under ## Guide instead. Known open item: the endpoint samples use AutoPay's own root-mounted paths (/subscriptions/...). Merchants reach these through a Connect proxy whose public path is in PR 121 and is not yet confirmed. Pending Yamen. Refs #158910 #158909
New page at /business/autopay/ for merchant admins and operations staff. One long page with a Pattern-A anchor sub-menu, matching what M-Wallet actually shipped rather than what its spec called for. Eleven sections, every heading carrying an explicit anchor id so renaming the visible text cannot silently break sidebars.ts. Right-hand table of contents kept. Zero code samples. All 22 of Menna's screenshots wired through <StepGuide>; every referenced image resolves to a real file. States plainly, as the ticket requires: - AutoPay never auto-cancels a past_due subscription — it stays past_due indefinitely until the customer pays or the merchant cancels - a customer cancellation always takes effect at the end of the current period; only the merchant can cancel immediately Merchant setup is documented as API-only. There is no merchant dashboard in this phase (confirmed by Dacian, 2026-08-13) and no merchant screenshots. No video — the Remotion pipeline is #158914 and is decoupled. Refs #158912 #158909 #158913
The Expired step claimed the page "still offers a way to pick things back up". Source says otherwise: - subscriptions/models.py has zero @transition with source=EXPIRED — it is a one-way terminal state - customer_api.py reactivate() requires status==ACTIVE AND cancel_at_period_end==true, and 422s otherwise; an expired subscription can never satisfy that Separately: portal-04-expired.png shows a Reactivate button that the backend would reject, and labels the date field "Trial Ends" under an Expired badge. Raised with the AutoPay self-service frontend owners — the screenshot looks like a mockup rather than real Expired-state UI. Refs #158912 #158913
158910 :: docs: AutoPay developer section
158912 :: docs: AutoPay business section
Three claims on the business page described the mockups rather than the product. Corrected against the screen data pack (autopay/docs/2026-08-13-autopay-screen-data-pack.md §2, §5): - AutoPay stores no invoice and no PDF. Dropped 'downloadable invoices' and 'invoice downloads'; a history row ends at its status. - There is no delete-card action. Cards are kept as history by design so an inactive card still explains an earlier cycle. Switching the active card is the only card management there is. - Pay Now only exists on a past-due subscription. Removed it from the active-state description. Also dropped the cards-01-delete-confirm.png reference — it depicts a flow that does not exist. Per the data pack it should be recut as a set-active-card confirm. Root cause worth recording: the mockups themselves are wrong (portal-01 shows an invoice Download column and a Pay Now button on an active subscription). The page described them faithfully. Backend-sourced behaviour was all correct; only screenshot-derived UI claims were affected. Refs #158912 #158913
… flag JWT gap Adversarial verification of both pages found three real defects. BLOCKER — retry_window_days is not a live field. It was removed by subscriptions/migrations/0028_drop_retry_window_days.py (2026-06-15) and appears nowhere outside migrations; the current SubscriptionInternalCreateIn has no such field. Sending it today is silently dropped. Documenting it with a 1-30 range misrepresented working behaviour. Note that ticket #158911's own field table still lists it — the ticket is stale, not the writer. MAJOR — the business page told readers Expired is terminal (correct: zero @transition with source=EXPIRED, and reactivate() requires status==ACTIVE) while displaying portal-04-expired.png, which shows a prominent Reactivate button. Dropped the screenshot rather than caption a contradiction. MAJOR — five of the six management endpoints need a Keycloak JWT and the page never said how to get one; the linked authentication guide covers only Api-Key. Added a :::warning naming it as an open gap so a reader is not left guessing. Known minor, not fixed: glossary terms added in this epic are not linked from the AutoPay page. Glossary term anchors do not exist in the built output at all (a pre-existing site-wide issue), so linking them would add broken anchors. Refs #158909 #158910 #158911 #158912
…duled cycle Found by visual verification in Chrome against the local production build. - AutoPayFlowDiagram: the 'ongoing' label's white background rect (x560-650) painted over the tail of 'creates subscription - sync' (x450-600), which rendered as 'creates subscriptior.'. Moved 'ongoing' below its own arrow. Verified in both light and dark mode. - Business page said customers 'look back through their full billing history'. The real betabulk portal shows the NEXT cycle in the same table with a Scheduled status, so the table is not past-only. Reworded. Refs #158909 #158910 #158912
Editorial pass against docs/business/wallet/index.md as the house reference. - Removed the only inline code span on the page. It was introduced by the Scheduled-cycle edit in a76caaf and broke the zero-code audience rule that #158912's acceptance criteria require. - Replaced $0 with 'zero' in three places. Ottu prices in KWD/SAR and the wallet business page uses no dollar signs at all. - 'pending setup' -> 'Pending setup' in the lifecycle table, matching the Title Case used for every other state name on the page. Refs #158912
Editorial pass against docs/business/wallet/index.md, measured before and after. Prose only — no structural, anchor, or image changes. - StepGuide captions 20 -> 13 words average (wallet reference: 7). Captions now point at the screenshot instead of arguing with it. - Em-dashes 20.3 -> 16.0 per 100 lines (wallet: 14.6). - Removed five marketing idioms with no precedent on the wallet page: 'without lifting a finger', 'in the driver's seat', 'doesn't move the needle', 'running a billing engine by hand', 'a heads-up'. Every factual claim is unchanged; this only affects how they are worded. Refs #158912
…cle statuses
Accuracy and consistency pass on both AutoPay pages, verified against
autopay/subscriptions/{enums,schemas}.py.
- notification_preferences: documented the three real boolean keys —
pre_charge_enabled, failure_enabled, final_failure_enabled, each
defaulting to true (schemas.py:52-54). Previously described only as
'free-form'.
- List subscriptions returns a slim summary per item, not the full
subscription object. Callers need Retrieve for the active card and
latest-cycle detail.
- Cycle statuses: added retry_scheduled and canceled, completing the set
a merchant can observe. needs_triage is deliberately omitted — it is an
ops-only state reached by stale-cleanup, not something a merchant acts on.
- US spelling for consistency with the rest of the docs: catalogue ->
catalog, cancelling -> canceling.
Refs #158909 #158910 #158912jab3z
commented
Aug 13, 2026
@claude review |
Claude finished @jab3z's task in 3m 14s —— View job Review complete
Note: Overall this is a strong, well-verified page pair — the sidebar anchor hygiene ( 1. "Copy-paste accurate" claim conflicts with the PR's own "base path unconfirmed" gap
But the PR description itself flags "Endpoint base path unconfirmed... Merchants reach these through a Connect proxy whose public path is in PR 121 — @yamen needs your answer." The six subscription-management cURL examples ( 2. New glossary terms aren't linked from either new page
3. Two shipped screenshots are never referenced, one contradicts the page copy
Not re-litigatedThe factual claims (write-only |
…rop mockups Three points from the PR 169 review. The API Reference note claimed every request and response above was copy-paste accurate, while the PR itself flags the Connect proxy prefix for the six management endpoints as unconfirmed. That gap was visible to reviewers and invisible to a reader on docs.ottu.dev. Replaced the claim with a warning under Step-by-Step naming exactly what is uncertain — the path in front of /subscriptions/ — and stating that the headers, bodies, responses and behaviour are not, and that Step 1's /b/checkout/v1/pymt-txn/ is the stable Checkout API path. Billing Cycle, Dunning and Subscription were added to glossary-terms.ts for this PR and nothing linked to them. Linked each once per page via /glossary/#term-<id>. GlossarySearch server-renders those ids, so the anchors resolve natively; Docusaurus still reports them broken because its checker only reads markdown headings — the same false positive already fires for the #term-* links on payment-states and transaction-states. portal-04-expired.png and cards-01-delete-confirm.png were unreferenced because both depict flows that do not exist: the first shows a Reactivate button on an Expired subscription (terminal in the backend) plus an invoice Download column, the second a delete-card confirmation. Dereferenced in b5475bf and 79835e2 respectively; deleting the assets so they cannot be wired back in. They need recapture from betabulk alongside portal-01-summary-active.png. npm run build passes.
ankitottu
commented
Aug 13, 2026
@claude re-review |
Claude finished @ankitottu's task in 1m 38s —— View job Re-review complete
Note: All three points from the first review are resolved cleanly in 1. "Copy-paste accurate" overclaim — fixed. 2. Glossary terms unlinked — fixed. 3. Unreferenced/contradictory screenshots — fixed correctly, not just papered over. Both One thing worth noting rather than re-flagging: Also scanned the intervening accuracy commit ( Nothing new surfaced in this pass. The two page diffs are clean additions with no leftover inconsistencies from the fix-up commits. |
Redmine epic #158909 — closes the docs half of the AutoPay launch.
Merges the epic branch into
dev, which deploys to docs.ottu.dev for review. Nothing reaches docs.ottu.com until it has been signed off there — that is #158915.What ships
/developers/payments/autopay/+AutoPayFlowDiagram+ glossary terms + payments-index entry/business/autopay/, one long page with a Pattern-A anchor sub-menudocs/superpowers/Both child PRs (#167, #168) already merged here.
sidebars.tswas edited once, in the scaffold commit, so the two lanes never touched the same file.The distinction the whole thing hangs on
recurring-payments.mdxis the closest existing page and readers will land on the wrong one, so both pages now cross-link with an explicit "use this when".Facts documented that appear in no ticket
Found by reading
autopay/subscriptions/and by a live betabulk call:autopayrequest block is write-only — not echoed in the 201.extra.autopay.subscription_idis the merchant's only handle. Verified live:sub_hA1YYmZz1xk8speCiPbOquIP.customer_emailis required. Omitting it 422s inside AutoPay and surfaces as400 {"autopay":["AutoPayClient rejected request (422)"]}— reads like an agreement-shape error and is not.page-linkdoes not rotate the token;regenerate-page-tokenrevokes. A merchant reaching for regenerate when they meant re-send silently breaks the customer's working link, with no notification to that customer.retry_window_daysis dead — dropped inmigrations/0028_drop_retry_window_days.py.listreturns a slim summary, not full subscription objects.Known gaps, deliberate
## API Referenceis a placeholdercore_backendPR 121 unmerged —static/Ottu_API.yamlhas zeroautopayoccurrences, so<ApiDocEmbed>cannot resolve. Endpoints documented as prose + cURL under## Guideinstead.:::warningon the page rather than papered over.Verification
npm run typecheck✅ ·npm run build✅onBrokenLinksis"warn", so a green build proves nothing about navigation:autopay/subscriptions/enums.py,models.py,schemas.pyortasks/_tenant_processors.pyportal-01-summary-active.pngis the hero image on the business page and it is a mockup that contradicts the real product. Checked against a live betabulk portal: it shows an invoice Download column (AutoPay stores no invoices), a Pay Now button on an active subscription (Pay Now only exists when past due), two cards both masked*** 1234, and a next-payment date a year adrift from its own history.The prose no longer describes any of it, but a reader still sees it. Recutting that one image — or a straight recapture from betabulk — is the highest-value screenshot task left. @junaid@Menna
Sign-off needed (#158915)
Do not merge until reviewed on this branch.