Uh oh!
There was an error while loading. Please reload this page.
158910 :: fix: correct merchant API auth, and stop disclosing internal topology - #170
Conversation
The six subscription-management endpoints were documented against AutoPay's internal service — wrong host path and wrong credential. Corrected against the real Connect proxy, verified live on betabulk. Auth was the substantive error. The page told developers to obtain a Keycloak JWT and send a Merchant-Id header, and carried a warning that the JWT flow 'isn't documented yet'. None of that is true for a merchant: Api-Key -> 200 no auth -> 401 Merchant-Id omitted -> 200 Merchants never reach AutoPay directly. Connect fronts it at /b/pbl/v2/subscriptions/ and resolves the merchant from the API key, so the same credential covers every call on the page. - rewrote the Step-by-Step auth section; deleted the JWT warning entirely - 6 sample URLs now carry the /b/pbl/v2 prefix - 6 Bearer headers -> Api-Key; 6 Merchant-Id headers removed - replaced the 'path isn't final' warning with a note distinguishing the two Connect surfaces: merchant API vs the customer page at /<lang>/subscription/<page_token> - retrieve response example now matches the live payload field-for-field (added setup_session_id, amount_variability, cycle_interval_days, total_cycles, cancellation_initiator/reason/note, description) Probed after the change: list, retrieve and cycles all 200. page-link 404s through the proxy under five path spellings and no page_url is exposed on retrieve, so a merchant currently has no documented way to fetch the customer link — open with Yamen. cancel and regenerate-page-token not probed, both destructive. Refs #158910 #158909 #158911
Merchants integrate against Connect. How Ottu routes a request internally is not their concern and does not belong on a public page. Removed from the developer page: - 'reach AutoPay through Ottu Connect at /b/pbl/v2/subscriptions/' - 'You never talk to AutoPay directly ... Connect resolves your merchant from the API key and forwards the call' - 'Ottu Connect commits and calls AutoPay synchronously' in the workflow, which described the internal hop rather than what the caller observes. Now states the merchant-visible fact: the result comes back on the same response, and a failure returns 4xx with no usable session_id. Removed from the flow diagram: - the separate 'Ottu Connect' and 'AutoPay' boxes and the internal 'creates subscription - sync' arrow between them. One 'AutoPay' box now stands for the platform; the ongoing box reads 'Handled for you' rather than 'Owned by AutoPay'. - the <desc> and alt text, which spelled the internal call out in full and ship to screen readers on every page load. The endpoint path itself stays — a caller needs the URL. What is gone is the narration of what sits behind it. Added a PUBLIC SURFACE note in the diagram source so the topology does not get reintroduced by a future edit. Refs #158910 #158909
ankitottu
commented
Aug 13, 2026
@claude review |
Claude finished @ankitottu's task in 2m 58s —— View job Review of PR #170 |
…AutoPay box Review catch on PR #170. Collapsing the two internal boxes left both inbound arrows terminating on the surviving box, which is labelled AutoPay: checkout call - auto_pay -> (330, 236) left edge of the AutoPay rect submits payment -> (552, 212) right edge of the same rect AutoPay rect = x 330-550, y 200-290 So the diagram claimed the customer's card payment is submitted to AutoPay and that the merchant's checkout call goes there directly. Hiding the internal routing was correct; asserting a different, wrong route was not. Both arrows now land on the OTTU PLATFORM container boundary instead (x 300-920, y 110-410) — the merchant calls the platform, the customer pays the platform, and AutoPay sits inside it as the step that creates the subscription. No service is credited with card processing either way. Kept the single box. The reviewer's alternative — restoring a second, generically-labelled box — would reintroduce the two-service shape that 5e3f825 deliberately removed. Refs #158910 #158909

Follow-up to #169. Two corrections to the AutoPay developer page that were made after that PR was already merged, so they need a second pass.
Redmine #158910 · epic #158909
1. The merchant API auth was wrong
The six subscription-management endpoints were documented against AutoPay's internal service — wrong path, wrong credential. The page told developers to obtain a Keycloak JWT and send a
Merchant-Idheader, and carried a warning that the JWT flow "isn't documented yet".None of that is true for a merchant. Verified live on betabulk:
.../subscriptions/.../b/pbl/v2/subscriptions/Authorization: Bearer <jwt_token>Authorization: Api-Key <YOUR_API_KEY>Merchant-Id:requiredAlso brought the retrieve response example in line with the live payload — added
setup_session_id,amount_variability,cycle_interval_days,total_cycles,cancellation_initiator/reason/note,description. Diffed field-by-field against a real response: zero differences either direction.2. The page disclosed internal service topology
Merchants integrate against Connect. How Ottu routes a request internally is not their concern and does not belong on a public page. Five disclosures removed:
Ottu Connect / Commits the transaction→AutoPay / Creates the subscription, with an internalcreates subscription · syncarrow between them. Now oneAutoPaybox; the ongoing box reads Handled for you rather than "Owned by AutoPay".<desc>andalttext — invisible in the browser, shipped to every screen reader, and spelled the topology out in full. This one would not have shown up in any review of the rendered page.Workflow step 2 now states the merchant-visible fact instead: the result comes back on the same response, not later by webhook; a failure returns 4xx with no usable
session_id.The endpoint path stays — a caller needs the URL. What is gone is narrating what sits behind it.
Added a
PUBLIC SURFACEnote in the diagram source so the topology does not get reintroduced by a future edit.Verification
npm run typecheck✅ ·npm run build✅Ottu Connect/forwards the call/talk to AutoPayacross both pages, the diagram source, and the served HTMLBearer/jwt/Merchant-Id;retry_window_daysgonepage-link404s through the proxy. Five path spellings tried, and there is nopage_urlon the retrieve response either — so a merchant currently has no documented way to fetch the customer's self-service link, which is the whole delivery mechanism for the customer page. Left documented rather than deleted, on the assumption it should exist. @yamen.cancelandregenerate-page-tokenare not probed — both are destructive.Knock-on:#158911's field table needs the same correction, or the enrichment YAML and the eventual
<ApiDocEmbed>will inherit the wrong base path and auth. That table also still listsretry_window_days, which was dropped inmigrations/0028_drop_retry_window_days.py.Do not merge until reviewed.