158910 :: fix: correct merchant API auth, and stop disclosing internal topology - #170

Merged
ankitottu merged 3 commits into
devfrom
epic/158909
Aug 13, 2026
Merged

158910 :: fix: correct merchant API auth, and stop disclosing internal topology#170
ankitottu merged 3 commits into
devfrom
epic/158909

Conversation

@ankitottu

Copy link
Copy Markdown
Contributor

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-Id header, and carried a warning that the JWT flow "isn't documented yet".

None of that is true for a merchant. Verified live on betabulk:

Api-Key -> 200
no auth -> 401
Merchant-Id omitted -> 200
BeforeAfter
Path.../subscriptions/.../b/pbl/v2/subscriptions/
CredentialAuthorization: Bearer <jwt_token>Authorization: Api-Key <YOUR_API_KEY>
Extra headerMerchant-Id: requirednot needed — removed
Warning block"Getting the JWT isn't documented yet"deleted; there is no JWT

Also 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:

  • "You never talk to AutoPay directly … Connect resolves your merchant from the API key and forwards the call"
  • "reach AutoPay through Ottu Connect at …"
  • Workflow step 2: "Ottu Connect commits and calls AutoPay synchronously …"
  • The flow diagram — two boxes, Ottu Connect / Commits the transactionAutoPay / Creates the subscription, with an internal creates subscription · sync arrow between them. Now one AutoPay box; the ongoing box reads Handled for you rather than "Owned by AutoPay".
  • The <desc> and alt text — 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 SURFACE note in the diagram source so the topology does not get reintroduced by a future edit.

Verification

POST /b/pbl/v2/subscriptions/ 200
GET /b/pbl/v2/subscriptions/{id}/ 200
GET /b/pbl/v2/subscriptions/{id}/cycles/ 200
  • npm run typecheck ✅ · npm run build
  • 0 matches for Ottu Connect / forwards the call / talk to AutoPay across both pages, the diagram source, and the served HTML
  • 0 matches for Bearer / jwt / Merchant-Id; retry_window_days gone
  • All 20 business-page images resolve
  • Diagram checked in Chrome in light and dark mode

⚠️ Still open

page-link 404s through the proxy. Five path spellings tried, and there is no page_url on 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.

cancel and regenerate-page-token are 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 lists retry_window_days, which was dropped in migrations/0028_drop_retry_window_days.py.

Do not merge until reviewed.

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

Copy link
Copy Markdown
ContributorAuthor

@claude review

@claude

claudeBot commented Aug 13, 2026

Copy link
Copy Markdown

Claude finished @ankitottu's task in 2m 58s —— View job


Review of PR #170

  • Gather context (diff, changed files, CLAUDE.md)
  • Review docs/developers/payments/autopay/index.mdx
  • Review src/diagrams/AutoPayFlowDiagram.tsx
  • Check verification claims (auth path, removed disclosures)
  • Post review feedback

Diffed both files against 34e4484 (the commit immediately preceding this PR's two commits — the repo is shallow-cloned so origin/dev...HEAD has no merge base, but the changed files match exactly).

Finding: the diagram's "submits payment" arrow now points at the wrong box

src/diagrams/AutoPayFlowDiagram.tsx — the AutoPay box (line 80) and the arrows that terminate on it (lines 92, 104).

Before this PR, the diagram had two accent boxes: Ottu Connect (Commits the transaction) and AutoPay (Creates the subscription). Two separate arrows fed them: the merchant's checkout call · auto_pay went into Connect, and the customer's submits payment (the CIT) also went into Connect — matching the removed accuracy-note comment that said "AutoPay never touches cardholder data. The CIT charge is processed by Ottu Connect."

This PR collapses the two boxes into one, labeled AutoPay, to stop disclosing the internal Connect→AutoPay hop — correct per the PR's own goal. But both arrows now terminate on that single box:

  • Line 92: checkout call · auto_pay → ends at (330, 236), inside the AutoPay rect (x 330–550, y 200–290, line 80).
  • Line 104: submits payment → ends at (552, 212), also inside/touching that same rect.

So the diagram now visually claims the customer's card payment is submitted directly to AutoPay, and that the merchant's checkout call goes to AutoPay rather than through the checkout/Connect layer. That's not a topology detail being hidden — it's a new factual claim, and it's the one thing the deleted comment explicitly said was false ("AutoPay never touches cardholder data"). Merging the boxes was the right call for hiding internal routing, but the box that survived still carries a specific label ("AutoPay / Creates the subscription") and both flows now read as going to that labeled entity.

Suggested fix (either works):

  • Re-route the submits payment arrow to end at the "Ottu Platform" container boundary (the dashed box, line 62) rather than the AutoPay rect specifically, so it doesn't visually attribute card processing to AutoPay, or
  • Keep two boxes but give the first a generic label (e.g. "Ottu Platform" or "Checkout") instead of removing it — satisfies "no internal service names" without merging distinct responsibilities into one.

The <desc>/alt text (lines 28, 117) don't have this problem — they only say "AutoPay creates the subscription synchronously," which is accurate and doesn't mention card processing.

Fix this →

Everything else checks out

  • Auth/path correction — every Bearer/jwt/Merchant-Id reference is gone from the mdx (verified via grep); all six endpoints now show Authorization: Api-Key <YOUR_API_KEY> against /b/pbl/v2/subscriptions/..., matching the PR's stated live verification.
  • Retrieve-response fields — the added fields (setup_session_id, amount_variability, cycle_interval_days, total_cycles, cancellation_initiator/reason/note, description) sit in valid JSON with correct comma placement.
  • New :::note replacing the two :::warning blocks — appropriate admonition choice per the root CLAUDE.md convention (:::note for clarifications vs. :::warning for gotchas), since there's no longer anything to warn about.
  • Anchor integrity — the new note links #customer-self-service-page, which exists at line 424 of the mdx (#### Customer Self-Service Page {#customer-self-service-page}); #step-by-step is unchanged.
  • Topology disclosures — confirmed removed from body text, workflow steps, and the diagram's <desc>/alt, matching the PR description.
  • Diagram box/arrow geometry otherwise stays within the "Ottu Platform" container and doesn't overlap the "Handled for you" box.

Not verified

I wasn't able to run npm run typecheck / npm run build myself — Bash execution required interactive approval in this environment and none was available. The PR description states both passed locally; the static diff review above doesn't contradict that (no syntax issues found in either file).
· branch epic/158909

…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
@ankitottu
ankitottu merged commit fb230bd into devAug 13, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@ankitottu
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

158910 :: fix: correct merchant API auth, and stop disclosing internal topology - #170

Merged
ankitottu merged 3 commits into
devfrom
epic/158909
Aug 13, 2026
Merged

158910 :: fix: correct merchant API auth, and stop disclosing internal topology#170
ankitottu merged 3 commits into
devfrom
epic/158909

Conversation

@ankitottu

Copy link
Copy Markdown
Contributor

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-Id header, and carried a warning that the JWT flow "isn't documented yet".

None of that is true for a merchant. Verified live on betabulk:

Api-Key -> 200
no auth -> 401
Merchant-Id omitted -> 200
BeforeAfter
Path.../subscriptions/.../b/pbl/v2/subscriptions/
CredentialAuthorization: Bearer <jwt_token>Authorization: Api-Key <YOUR_API_KEY>
Extra headerMerchant-Id: requirednot needed — removed
Warning block"Getting the JWT isn't documented yet"deleted; there is no JWT

Also 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:

  • "You never talk to AutoPay directly … Connect resolves your merchant from the API key and forwards the call"
  • "reach AutoPay through Ottu Connect at …"
  • Workflow step 2: "Ottu Connect commits and calls AutoPay synchronously …"
  • The flow diagram — two boxes, Ottu Connect / Commits the transactionAutoPay / Creates the subscription, with an internal creates subscription · sync arrow between them. Now one AutoPay box; the ongoing box reads Handled for you rather than "Owned by AutoPay".
  • The <desc> and alt text — 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 SURFACE note in the diagram source so the topology does not get reintroduced by a future edit.

Verification

POST /b/pbl/v2/subscriptions/ 200
GET /b/pbl/v2/subscriptions/{id}/ 200
GET /b/pbl/v2/subscriptions/{id}/cycles/ 200
  • npm run typecheck ✅ · npm run build
  • 0 matches for Ottu Connect / forwards the call / talk to AutoPay across both pages, the diagram source, and the served HTML
  • 0 matches for Bearer / jwt / Merchant-Id; retry_window_days gone
  • All 20 business-page images resolve
  • Diagram checked in Chrome in light and dark mode

⚠️ Still open

page-link 404s through the proxy. Five path spellings tried, and there is no page_url on 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.

cancel and regenerate-page-token are 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 lists retry_window_days, which was dropped in migrations/0028_drop_retry_window_days.py.

Do not merge until reviewed.

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

Copy link
Copy Markdown
ContributorAuthor

@claude review

@claude

claudeBot commented Aug 13, 2026

Copy link
Copy Markdown

Claude finished @ankitottu's task in 2m 58s —— View job


Review of PR #170

  • Gather context (diff, changed files, CLAUDE.md)
  • Review docs/developers/payments/autopay/index.mdx
  • Review src/diagrams/AutoPayFlowDiagram.tsx
  • Check verification claims (auth path, removed disclosures)
  • Post review feedback

Diffed both files against 34e4484 (the commit immediately preceding this PR's two commits — the repo is shallow-cloned so origin/dev...HEAD has no merge base, but the changed files match exactly).

Finding: the diagram's "submits payment" arrow now points at the wrong box

src/diagrams/AutoPayFlowDiagram.tsx — the AutoPay box (line 80) and the arrows that terminate on it (lines 92, 104).

Before this PR, the diagram had two accent boxes: Ottu Connect (Commits the transaction) and AutoPay (Creates the subscription). Two separate arrows fed them: the merchant's checkout call · auto_pay went into Connect, and the customer's submits payment (the CIT) also went into Connect — matching the removed accuracy-note comment that said "AutoPay never touches cardholder data. The CIT charge is processed by Ottu Connect."

This PR collapses the two boxes into one, labeled AutoPay, to stop disclosing the internal Connect→AutoPay hop — correct per the PR's own goal. But both arrows now terminate on that single box:

  • Line 92: checkout call · auto_pay → ends at (330, 236), inside the AutoPay rect (x 330–550, y 200–290, line 80).
  • Line 104: submits payment → ends at (552, 212), also inside/touching that same rect.

So the diagram now visually claims the customer's card payment is submitted directly to AutoPay, and that the merchant's checkout call goes to AutoPay rather than through the checkout/Connect layer. That's not a topology detail being hidden — it's a new factual claim, and it's the one thing the deleted comment explicitly said was false ("AutoPay never touches cardholder data"). Merging the boxes was the right call for hiding internal routing, but the box that survived still carries a specific label ("AutoPay / Creates the subscription") and both flows now read as going to that labeled entity.

Suggested fix (either works):

  • Re-route the submits payment arrow to end at the "Ottu Platform" container boundary (the dashed box, line 62) rather than the AutoPay rect specifically, so it doesn't visually attribute card processing to AutoPay, or
  • Keep two boxes but give the first a generic label (e.g. "Ottu Platform" or "Checkout") instead of removing it — satisfies "no internal service names" without merging distinct responsibilities into one.

The <desc>/alt text (lines 28, 117) don't have this problem — they only say "AutoPay creates the subscription synchronously," which is accurate and doesn't mention card processing.

Fix this →

Everything else checks out

  • Auth/path correction — every Bearer/jwt/Merchant-Id reference is gone from the mdx (verified via grep); all six endpoints now show Authorization: Api-Key <YOUR_API_KEY> against /b/pbl/v2/subscriptions/..., matching the PR's stated live verification.
  • Retrieve-response fields — the added fields (setup_session_id, amount_variability, cycle_interval_days, total_cycles, cancellation_initiator/reason/note, description) sit in valid JSON with correct comma placement.
  • New :::note replacing the two :::warning blocks — appropriate admonition choice per the root CLAUDE.md convention (:::note for clarifications vs. :::warning for gotchas), since there's no longer anything to warn about.
  • Anchor integrity — the new note links #customer-self-service-page, which exists at line 424 of the mdx (#### Customer Self-Service Page {#customer-self-service-page}); #step-by-step is unchanged.
  • Topology disclosures — confirmed removed from body text, workflow steps, and the diagram's <desc>/alt, matching the PR description.
  • Diagram box/arrow geometry otherwise stays within the "Ottu Platform" container and doesn't overlap the "Handled for you" box.

Not verified

I wasn't able to run npm run typecheck / npm run build myself — Bash execution required interactive approval in this environment and none was available. The PR description states both passed locally; the static diff review above doesn't contradict that (no syntax issues found in either file).
· branch epic/158909

…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
@ankitottu
ankitottu merged commit fb230bd into devAug 13, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@ankitottu
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

158910 :: fix: correct merchant API auth, and stop disclosing internal topology - #170

Merged
ankitottu merged 3 commits into
devfrom
epic/158909
Aug 13, 2026
Merged

158910 :: fix: correct merchant API auth, and stop disclosing internal topology#170
ankitottu merged 3 commits into
devfrom
epic/158909

Conversation

@ankitottu

Copy link
Copy Markdown
Contributor

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-Id header, and carried a warning that the JWT flow "isn't documented yet".

None of that is true for a merchant. Verified live on betabulk:

Api-Key -> 200
no auth -> 401
Merchant-Id omitted -> 200
BeforeAfter
Path.../subscriptions/.../b/pbl/v2/subscriptions/
CredentialAuthorization: Bearer <jwt_token>Authorization: Api-Key <YOUR_API_KEY>
Extra headerMerchant-Id: requirednot needed — removed
Warning block"Getting the JWT isn't documented yet"deleted; there is no JWT

Also 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:

  • "You never talk to AutoPay directly … Connect resolves your merchant from the API key and forwards the call"
  • "reach AutoPay through Ottu Connect at …"
  • Workflow step 2: "Ottu Connect commits and calls AutoPay synchronously …"
  • The flow diagram — two boxes, Ottu Connect / Commits the transactionAutoPay / Creates the subscription, with an internal creates subscription · sync arrow between them. Now one AutoPay box; the ongoing box reads Handled for you rather than "Owned by AutoPay".
  • The <desc> and alt text — 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 SURFACE note in the diagram source so the topology does not get reintroduced by a future edit.

Verification

POST /b/pbl/v2/subscriptions/ 200
GET /b/pbl/v2/subscriptions/{id}/ 200
GET /b/pbl/v2/subscriptions/{id}/cycles/ 200
  • npm run typecheck ✅ · npm run build
  • 0 matches for Ottu Connect / forwards the call / talk to AutoPay across both pages, the diagram source, and the served HTML
  • 0 matches for Bearer / jwt / Merchant-Id; retry_window_days gone
  • All 20 business-page images resolve
  • Diagram checked in Chrome in light and dark mode

⚠️ Still open

page-link 404s through the proxy. Five path spellings tried, and there is no page_url on 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.

cancel and regenerate-page-token are 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 lists retry_window_days, which was dropped in migrations/0028_drop_retry_window_days.py.

Do not merge until reviewed.

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

Copy link
Copy Markdown
ContributorAuthor

@claude review

@claude

claudeBot commented Aug 13, 2026

Copy link
Copy Markdown

Claude finished @ankitottu's task in 2m 58s —— View job


Review of PR #170

  • Gather context (diff, changed files, CLAUDE.md)
  • Review docs/developers/payments/autopay/index.mdx
  • Review src/diagrams/AutoPayFlowDiagram.tsx
  • Check verification claims (auth path, removed disclosures)
  • Post review feedback

Diffed both files against 34e4484 (the commit immediately preceding this PR's two commits — the repo is shallow-cloned so origin/dev...HEAD has no merge base, but the changed files match exactly).

Finding: the diagram's "submits payment" arrow now points at the wrong box

src/diagrams/AutoPayFlowDiagram.tsx — the AutoPay box (line 80) and the arrows that terminate on it (lines 92, 104).

Before this PR, the diagram had two accent boxes: Ottu Connect (Commits the transaction) and AutoPay (Creates the subscription). Two separate arrows fed them: the merchant's checkout call · auto_pay went into Connect, and the customer's submits payment (the CIT) also went into Connect — matching the removed accuracy-note comment that said "AutoPay never touches cardholder data. The CIT charge is processed by Ottu Connect."

This PR collapses the two boxes into one, labeled AutoPay, to stop disclosing the internal Connect→AutoPay hop — correct per the PR's own goal. But both arrows now terminate on that single box:

  • Line 92: checkout call · auto_pay → ends at (330, 236), inside the AutoPay rect (x 330–550, y 200–290, line 80).
  • Line 104: submits payment → ends at (552, 212), also inside/touching that same rect.

So the diagram now visually claims the customer's card payment is submitted directly to AutoPay, and that the merchant's checkout call goes to AutoPay rather than through the checkout/Connect layer. That's not a topology detail being hidden — it's a new factual claim, and it's the one thing the deleted comment explicitly said was false ("AutoPay never touches cardholder data"). Merging the boxes was the right call for hiding internal routing, but the box that survived still carries a specific label ("AutoPay / Creates the subscription") and both flows now read as going to that labeled entity.

Suggested fix (either works):

  • Re-route the submits payment arrow to end at the "Ottu Platform" container boundary (the dashed box, line 62) rather than the AutoPay rect specifically, so it doesn't visually attribute card processing to AutoPay, or
  • Keep two boxes but give the first a generic label (e.g. "Ottu Platform" or "Checkout") instead of removing it — satisfies "no internal service names" without merging distinct responsibilities into one.

The <desc>/alt text (lines 28, 117) don't have this problem — they only say "AutoPay creates the subscription synchronously," which is accurate and doesn't mention card processing.

Fix this →

Everything else checks out

  • Auth/path correction — every Bearer/jwt/Merchant-Id reference is gone from the mdx (verified via grep); all six endpoints now show Authorization: Api-Key <YOUR_API_KEY> against /b/pbl/v2/subscriptions/..., matching the PR's stated live verification.
  • Retrieve-response fields — the added fields (setup_session_id, amount_variability, cycle_interval_days, total_cycles, cancellation_initiator/reason/note, description) sit in valid JSON with correct comma placement.
  • New :::note replacing the two :::warning blocks — appropriate admonition choice per the root CLAUDE.md convention (:::note for clarifications vs. :::warning for gotchas), since there's no longer anything to warn about.
  • Anchor integrity — the new note links #customer-self-service-page, which exists at line 424 of the mdx (#### Customer Self-Service Page {#customer-self-service-page}); #step-by-step is unchanged.
  • Topology disclosures — confirmed removed from body text, workflow steps, and the diagram's <desc>/alt, matching the PR description.
  • Diagram box/arrow geometry otherwise stays within the "Ottu Platform" container and doesn't overlap the "Handled for you" box.

Not verified

I wasn't able to run npm run typecheck / npm run build myself — Bash execution required interactive approval in this environment and none was available. The PR description states both passed locally; the static diff review above doesn't contradict that (no syntax issues found in either file).
· branch epic/158909

…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
@ankitottu
ankitottu merged commit fb230bd into devAug 13, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@ankitottu
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

158910 :: fix: correct merchant API auth, and stop disclosing internal topology - #170

Merged
ankitottu merged 3 commits into
devfrom
epic/158909
Aug 13, 2026
Merged

158910 :: fix: correct merchant API auth, and stop disclosing internal topology#170
ankitottu merged 3 commits into
devfrom
epic/158909

Conversation

@ankitottu

Copy link
Copy Markdown
Contributor

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-Id header, and carried a warning that the JWT flow "isn't documented yet".

None of that is true for a merchant. Verified live on betabulk:

Api-Key -> 200
no auth -> 401
Merchant-Id omitted -> 200
BeforeAfter
Path.../subscriptions/.../b/pbl/v2/subscriptions/
CredentialAuthorization: Bearer <jwt_token>Authorization: Api-Key <YOUR_API_KEY>
Extra headerMerchant-Id: requirednot needed — removed
Warning block"Getting the JWT isn't documented yet"deleted; there is no JWT

Also 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:

  • "You never talk to AutoPay directly … Connect resolves your merchant from the API key and forwards the call"
  • "reach AutoPay through Ottu Connect at …"
  • Workflow step 2: "Ottu Connect commits and calls AutoPay synchronously …"
  • The flow diagram — two boxes, Ottu Connect / Commits the transactionAutoPay / Creates the subscription, with an internal creates subscription · sync arrow between them. Now one AutoPay box; the ongoing box reads Handled for you rather than "Owned by AutoPay".
  • The <desc> and alt text — 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 SURFACE note in the diagram source so the topology does not get reintroduced by a future edit.

Verification

POST /b/pbl/v2/subscriptions/ 200
GET /b/pbl/v2/subscriptions/{id}/ 200
GET /b/pbl/v2/subscriptions/{id}/cycles/ 200
  • npm run typecheck ✅ · npm run build
  • 0 matches for Ottu Connect / forwards the call / talk to AutoPay across both pages, the diagram source, and the served HTML
  • 0 matches for Bearer / jwt / Merchant-Id; retry_window_days gone
  • All 20 business-page images resolve
  • Diagram checked in Chrome in light and dark mode

⚠️ Still open

page-link 404s through the proxy. Five path spellings tried, and there is no page_url on 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.

cancel and regenerate-page-token are 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 lists retry_window_days, which was dropped in migrations/0028_drop_retry_window_days.py.

Do not merge until reviewed.

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

Copy link
Copy Markdown
ContributorAuthor

@claude review

@claude

claudeBot commented Aug 13, 2026

Copy link
Copy Markdown

Claude finished @ankitottu's task in 2m 58s —— View job


Review of PR #170

  • Gather context (diff, changed files, CLAUDE.md)
  • Review docs/developers/payments/autopay/index.mdx
  • Review src/diagrams/AutoPayFlowDiagram.tsx
  • Check verification claims (auth path, removed disclosures)
  • Post review feedback

Diffed both files against 34e4484 (the commit immediately preceding this PR's two commits — the repo is shallow-cloned so origin/dev...HEAD has no merge base, but the changed files match exactly).

Finding: the diagram's "submits payment" arrow now points at the wrong box

src/diagrams/AutoPayFlowDiagram.tsx — the AutoPay box (line 80) and the arrows that terminate on it (lines 92, 104).

Before this PR, the diagram had two accent boxes: Ottu Connect (Commits the transaction) and AutoPay (Creates the subscription). Two separate arrows fed them: the merchant's checkout call · auto_pay went into Connect, and the customer's submits payment (the CIT) also went into Connect — matching the removed accuracy-note comment that said "AutoPay never touches cardholder data. The CIT charge is processed by Ottu Connect."

This PR collapses the two boxes into one, labeled AutoPay, to stop disclosing the internal Connect→AutoPay hop — correct per the PR's own goal. But both arrows now terminate on that single box:

  • Line 92: checkout call · auto_pay → ends at (330, 236), inside the AutoPay rect (x 330–550, y 200–290, line 80).
  • Line 104: submits payment → ends at (552, 212), also inside/touching that same rect.

So the diagram now visually claims the customer's card payment is submitted directly to AutoPay, and that the merchant's checkout call goes to AutoPay rather than through the checkout/Connect layer. That's not a topology detail being hidden — it's a new factual claim, and it's the one thing the deleted comment explicitly said was false ("AutoPay never touches cardholder data"). Merging the boxes was the right call for hiding internal routing, but the box that survived still carries a specific label ("AutoPay / Creates the subscription") and both flows now read as going to that labeled entity.

Suggested fix (either works):

  • Re-route the submits payment arrow to end at the "Ottu Platform" container boundary (the dashed box, line 62) rather than the AutoPay rect specifically, so it doesn't visually attribute card processing to AutoPay, or
  • Keep two boxes but give the first a generic label (e.g. "Ottu Platform" or "Checkout") instead of removing it — satisfies "no internal service names" without merging distinct responsibilities into one.

The <desc>/alt text (lines 28, 117) don't have this problem — they only say "AutoPay creates the subscription synchronously," which is accurate and doesn't mention card processing.

Fix this →

Everything else checks out

  • Auth/path correction — every Bearer/jwt/Merchant-Id reference is gone from the mdx (verified via grep); all six endpoints now show Authorization: Api-Key <YOUR_API_KEY> against /b/pbl/v2/subscriptions/..., matching the PR's stated live verification.
  • Retrieve-response fields — the added fields (setup_session_id, amount_variability, cycle_interval_days, total_cycles, cancellation_initiator/reason/note, description) sit in valid JSON with correct comma placement.
  • New :::note replacing the two :::warning blocks — appropriate admonition choice per the root CLAUDE.md convention (:::note for clarifications vs. :::warning for gotchas), since there's no longer anything to warn about.
  • Anchor integrity — the new note links #customer-self-service-page, which exists at line 424 of the mdx (#### Customer Self-Service Page {#customer-self-service-page}); #step-by-step is unchanged.
  • Topology disclosures — confirmed removed from body text, workflow steps, and the diagram's <desc>/alt, matching the PR description.
  • Diagram box/arrow geometry otherwise stays within the "Ottu Platform" container and doesn't overlap the "Handled for you" box.

Not verified

I wasn't able to run npm run typecheck / npm run build myself — Bash execution required interactive approval in this environment and none was available. The PR description states both passed locally; the static diff review above doesn't contradict that (no syntax issues found in either file).
· branch epic/158909

…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
@ankitottu
ankitottu merged commit fb230bd into devAug 13, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@ankitottu
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

158910 :: fix: correct merchant API auth, and stop disclosing internal topology - #170

Merged
ankitottu merged 3 commits into
devfrom
epic/158909
Aug 13, 2026
Merged

158910 :: fix: correct merchant API auth, and stop disclosing internal topology#170
ankitottu merged 3 commits into
devfrom
epic/158909

Conversation

@ankitottu

Copy link
Copy Markdown
Contributor

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-Id header, and carried a warning that the JWT flow "isn't documented yet".

None of that is true for a merchant. Verified live on betabulk:

Api-Key -> 200
no auth -> 401
Merchant-Id omitted -> 200
BeforeAfter
Path.../subscriptions/.../b/pbl/v2/subscriptions/
CredentialAuthorization: Bearer <jwt_token>Authorization: Api-Key <YOUR_API_KEY>
Extra headerMerchant-Id: requirednot needed — removed
Warning block"Getting the JWT isn't documented yet"deleted; there is no JWT

Also 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:

  • "You never talk to AutoPay directly … Connect resolves your merchant from the API key and forwards the call"
  • "reach AutoPay through Ottu Connect at …"
  • Workflow step 2: "Ottu Connect commits and calls AutoPay synchronously …"
  • The flow diagram — two boxes, Ottu Connect / Commits the transactionAutoPay / Creates the subscription, with an internal creates subscription · sync arrow between them. Now one AutoPay box; the ongoing box reads Handled for you rather than "Owned by AutoPay".
  • The <desc> and alt text — 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 SURFACE note in the diagram source so the topology does not get reintroduced by a future edit.

Verification

POST /b/pbl/v2/subscriptions/ 200
GET /b/pbl/v2/subscriptions/{id}/ 200
GET /b/pbl/v2/subscriptions/{id}/cycles/ 200
  • npm run typecheck ✅ · npm run build
  • 0 matches for Ottu Connect / forwards the call / talk to AutoPay across both pages, the diagram source, and the served HTML
  • 0 matches for Bearer / jwt / Merchant-Id; retry_window_days gone
  • All 20 business-page images resolve
  • Diagram checked in Chrome in light and dark mode

⚠️ Still open

page-link 404s through the proxy. Five path spellings tried, and there is no page_url on 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.

cancel and regenerate-page-token are 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 lists retry_window_days, which was dropped in migrations/0028_drop_retry_window_days.py.

Do not merge until reviewed.

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

Copy link
Copy Markdown
ContributorAuthor

@claude review

@claude

claudeBot commented Aug 13, 2026

Copy link
Copy Markdown

Claude finished @ankitottu's task in 2m 58s —— View job


Review of PR #170

  • Gather context (diff, changed files, CLAUDE.md)
  • Review docs/developers/payments/autopay/index.mdx
  • Review src/diagrams/AutoPayFlowDiagram.tsx
  • Check verification claims (auth path, removed disclosures)
  • Post review feedback

Diffed both files against 34e4484 (the commit immediately preceding this PR's two commits — the repo is shallow-cloned so origin/dev...HEAD has no merge base, but the changed files match exactly).

Finding: the diagram's "submits payment" arrow now points at the wrong box

src/diagrams/AutoPayFlowDiagram.tsx — the AutoPay box (line 80) and the arrows that terminate on it (lines 92, 104).

Before this PR, the diagram had two accent boxes: Ottu Connect (Commits the transaction) and AutoPay (Creates the subscription). Two separate arrows fed them: the merchant's checkout call · auto_pay went into Connect, and the customer's submits payment (the CIT) also went into Connect — matching the removed accuracy-note comment that said "AutoPay never touches cardholder data. The CIT charge is processed by Ottu Connect."

This PR collapses the two boxes into one, labeled AutoPay, to stop disclosing the internal Connect→AutoPay hop — correct per the PR's own goal. But both arrows now terminate on that single box:

  • Line 92: checkout call · auto_pay → ends at (330, 236), inside the AutoPay rect (x 330–550, y 200–290, line 80).
  • Line 104: submits payment → ends at (552, 212), also inside/touching that same rect.

So the diagram now visually claims the customer's card payment is submitted directly to AutoPay, and that the merchant's checkout call goes to AutoPay rather than through the checkout/Connect layer. That's not a topology detail being hidden — it's a new factual claim, and it's the one thing the deleted comment explicitly said was false ("AutoPay never touches cardholder data"). Merging the boxes was the right call for hiding internal routing, but the box that survived still carries a specific label ("AutoPay / Creates the subscription") and both flows now read as going to that labeled entity.

Suggested fix (either works):

  • Re-route the submits payment arrow to end at the "Ottu Platform" container boundary (the dashed box, line 62) rather than the AutoPay rect specifically, so it doesn't visually attribute card processing to AutoPay, or
  • Keep two boxes but give the first a generic label (e.g. "Ottu Platform" or "Checkout") instead of removing it — satisfies "no internal service names" without merging distinct responsibilities into one.

The <desc>/alt text (lines 28, 117) don't have this problem — they only say "AutoPay creates the subscription synchronously," which is accurate and doesn't mention card processing.

Fix this →

Everything else checks out

  • Auth/path correction — every Bearer/jwt/Merchant-Id reference is gone from the mdx (verified via grep); all six endpoints now show Authorization: Api-Key <YOUR_API_KEY> against /b/pbl/v2/subscriptions/..., matching the PR's stated live verification.
  • Retrieve-response fields — the added fields (setup_session_id, amount_variability, cycle_interval_days, total_cycles, cancellation_initiator/reason/note, description) sit in valid JSON with correct comma placement.
  • New :::note replacing the two :::warning blocks — appropriate admonition choice per the root CLAUDE.md convention (:::note for clarifications vs. :::warning for gotchas), since there's no longer anything to warn about.
  • Anchor integrity — the new note links #customer-self-service-page, which exists at line 424 of the mdx (#### Customer Self-Service Page {#customer-self-service-page}); #step-by-step is unchanged.
  • Topology disclosures — confirmed removed from body text, workflow steps, and the diagram's <desc>/alt, matching the PR description.
  • Diagram box/arrow geometry otherwise stays within the "Ottu Platform" container and doesn't overlap the "Handled for you" box.

Not verified

I wasn't able to run npm run typecheck / npm run build myself — Bash execution required interactive approval in this environment and none was available. The PR description states both passed locally; the static diff review above doesn't contradict that (no syntax issues found in either file).
· branch epic/158909

…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
@ankitottu
ankitottu merged commit fb230bd into devAug 13, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@ankitottu
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

158910 :: fix: correct merchant API auth, and stop disclosing internal topology - #170

Merged
ankitottu merged 3 commits into
devfrom
epic/158909
Aug 13, 2026
Merged

158910 :: fix: correct merchant API auth, and stop disclosing internal topology#170
ankitottu merged 3 commits into
devfrom
epic/158909

Conversation

@ankitottu

Copy link
Copy Markdown
Contributor

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-Id header, and carried a warning that the JWT flow "isn't documented yet".

None of that is true for a merchant. Verified live on betabulk:

Api-Key -> 200
no auth -> 401
Merchant-Id omitted -> 200
BeforeAfter
Path.../subscriptions/.../b/pbl/v2/subscriptions/
CredentialAuthorization: Bearer <jwt_token>Authorization: Api-Key <YOUR_API_KEY>
Extra headerMerchant-Id: requirednot needed — removed
Warning block"Getting the JWT isn't documented yet"deleted; there is no JWT

Also 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:

  • "You never talk to AutoPay directly … Connect resolves your merchant from the API key and forwards the call"
  • "reach AutoPay through Ottu Connect at …"
  • Workflow step 2: "Ottu Connect commits and calls AutoPay synchronously …"
  • The flow diagram — two boxes, Ottu Connect / Commits the transactionAutoPay / Creates the subscription, with an internal creates subscription · sync arrow between them. Now one AutoPay box; the ongoing box reads Handled for you rather than "Owned by AutoPay".
  • The <desc> and alt text — 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 SURFACE note in the diagram source so the topology does not get reintroduced by a future edit.

Verification

POST /b/pbl/v2/subscriptions/ 200
GET /b/pbl/v2/subscriptions/{id}/ 200
GET /b/pbl/v2/subscriptions/{id}/cycles/ 200
  • npm run typecheck ✅ · npm run build
  • 0 matches for Ottu Connect / forwards the call / talk to AutoPay across both pages, the diagram source, and the served HTML
  • 0 matches for Bearer / jwt / Merchant-Id; retry_window_days gone
  • All 20 business-page images resolve
  • Diagram checked in Chrome in light and dark mode

⚠️ Still open

page-link 404s through the proxy. Five path spellings tried, and there is no page_url on 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.

cancel and regenerate-page-token are 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 lists retry_window_days, which was dropped in migrations/0028_drop_retry_window_days.py.

Do not merge until reviewed.

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

Copy link
Copy Markdown
ContributorAuthor

@claude review

@claude

claudeBot commented Aug 13, 2026

Copy link
Copy Markdown

Claude finished @ankitottu's task in 2m 58s —— View job


Review of PR #170

  • Gather context (diff, changed files, CLAUDE.md)
  • Review docs/developers/payments/autopay/index.mdx
  • Review src/diagrams/AutoPayFlowDiagram.tsx
  • Check verification claims (auth path, removed disclosures)
  • Post review feedback

Diffed both files against 34e4484 (the commit immediately preceding this PR's two commits — the repo is shallow-cloned so origin/dev...HEAD has no merge base, but the changed files match exactly).

Finding: the diagram's "submits payment" arrow now points at the wrong box

src/diagrams/AutoPayFlowDiagram.tsx — the AutoPay box (line 80) and the arrows that terminate on it (lines 92, 104).

Before this PR, the diagram had two accent boxes: Ottu Connect (Commits the transaction) and AutoPay (Creates the subscription). Two separate arrows fed them: the merchant's checkout call · auto_pay went into Connect, and the customer's submits payment (the CIT) also went into Connect — matching the removed accuracy-note comment that said "AutoPay never touches cardholder data. The CIT charge is processed by Ottu Connect."

This PR collapses the two boxes into one, labeled AutoPay, to stop disclosing the internal Connect→AutoPay hop — correct per the PR's own goal. But both arrows now terminate on that single box:

  • Line 92: checkout call · auto_pay → ends at (330, 236), inside the AutoPay rect (x 330–550, y 200–290, line 80).
  • Line 104: submits payment → ends at (552, 212), also inside/touching that same rect.

So the diagram now visually claims the customer's card payment is submitted directly to AutoPay, and that the merchant's checkout call goes to AutoPay rather than through the checkout/Connect layer. That's not a topology detail being hidden — it's a new factual claim, and it's the one thing the deleted comment explicitly said was false ("AutoPay never touches cardholder data"). Merging the boxes was the right call for hiding internal routing, but the box that survived still carries a specific label ("AutoPay / Creates the subscription") and both flows now read as going to that labeled entity.

Suggested fix (either works):

  • Re-route the submits payment arrow to end at the "Ottu Platform" container boundary (the dashed box, line 62) rather than the AutoPay rect specifically, so it doesn't visually attribute card processing to AutoPay, or
  • Keep two boxes but give the first a generic label (e.g. "Ottu Platform" or "Checkout") instead of removing it — satisfies "no internal service names" without merging distinct responsibilities into one.

The <desc>/alt text (lines 28, 117) don't have this problem — they only say "AutoPay creates the subscription synchronously," which is accurate and doesn't mention card processing.

Fix this →

Everything else checks out

  • Auth/path correction — every Bearer/jwt/Merchant-Id reference is gone from the mdx (verified via grep); all six endpoints now show Authorization: Api-Key <YOUR_API_KEY> against /b/pbl/v2/subscriptions/..., matching the PR's stated live verification.
  • Retrieve-response fields — the added fields (setup_session_id, amount_variability, cycle_interval_days, total_cycles, cancellation_initiator/reason/note, description) sit in valid JSON with correct comma placement.
  • New :::note replacing the two :::warning blocks — appropriate admonition choice per the root CLAUDE.md convention (:::note for clarifications vs. :::warning for gotchas), since there's no longer anything to warn about.
  • Anchor integrity — the new note links #customer-self-service-page, which exists at line 424 of the mdx (#### Customer Self-Service Page {#customer-self-service-page}); #step-by-step is unchanged.
  • Topology disclosures — confirmed removed from body text, workflow steps, and the diagram's <desc>/alt, matching the PR description.
  • Diagram box/arrow geometry otherwise stays within the "Ottu Platform" container and doesn't overlap the "Handled for you" box.

Not verified

I wasn't able to run npm run typecheck / npm run build myself — Bash execution required interactive approval in this environment and none was available. The PR description states both passed locally; the static diff review above doesn't contradict that (no syntax issues found in either file).
· branch epic/158909

…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
@ankitottu
ankitottu merged commit fb230bd into devAug 13, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@ankitottu
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

158910 :: fix: correct merchant API auth, and stop disclosing internal topology - #170

Merged
ankitottu merged 3 commits into
devfrom
epic/158909
Aug 13, 2026
Merged

158910 :: fix: correct merchant API auth, and stop disclosing internal topology#170
ankitottu merged 3 commits into
devfrom
epic/158909

Conversation

@ankitottu

Copy link
Copy Markdown
Contributor

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-Id header, and carried a warning that the JWT flow "isn't documented yet".

None of that is true for a merchant. Verified live on betabulk:

Api-Key -> 200
no auth -> 401
Merchant-Id omitted -> 200
BeforeAfter
Path.../subscriptions/.../b/pbl/v2/subscriptions/
CredentialAuthorization: Bearer <jwt_token>Authorization: Api-Key <YOUR_API_KEY>
Extra headerMerchant-Id: requirednot needed — removed
Warning block"Getting the JWT isn't documented yet"deleted; there is no JWT

Also 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:

  • "You never talk to AutoPay directly … Connect resolves your merchant from the API key and forwards the call"
  • "reach AutoPay through Ottu Connect at …"
  • Workflow step 2: "Ottu Connect commits and calls AutoPay synchronously …"
  • The flow diagram — two boxes, Ottu Connect / Commits the transactionAutoPay / Creates the subscription, with an internal creates subscription · sync arrow between them. Now one AutoPay box; the ongoing box reads Handled for you rather than "Owned by AutoPay".
  • The <desc> and alt text — 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 SURFACE note in the diagram source so the topology does not get reintroduced by a future edit.

Verification

POST /b/pbl/v2/subscriptions/ 200
GET /b/pbl/v2/subscriptions/{id}/ 200
GET /b/pbl/v2/subscriptions/{id}/cycles/ 200
  • npm run typecheck ✅ · npm run build
  • 0 matches for Ottu Connect / forwards the call / talk to AutoPay across both pages, the diagram source, and the served HTML
  • 0 matches for Bearer / jwt / Merchant-Id; retry_window_days gone
  • All 20 business-page images resolve
  • Diagram checked in Chrome in light and dark mode

⚠️ Still open

page-link 404s through the proxy. Five path spellings tried, and there is no page_url on 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.

cancel and regenerate-page-token are 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 lists retry_window_days, which was dropped in migrations/0028_drop_retry_window_days.py.

Do not merge until reviewed.

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

Copy link
Copy Markdown
ContributorAuthor

@claude review

@claude

claudeBot commented Aug 13, 2026

Copy link
Copy Markdown

Claude finished @ankitottu's task in 2m 58s —— View job


Review of PR #170

  • Gather context (diff, changed files, CLAUDE.md)
  • Review docs/developers/payments/autopay/index.mdx
  • Review src/diagrams/AutoPayFlowDiagram.tsx
  • Check verification claims (auth path, removed disclosures)
  • Post review feedback

Diffed both files against 34e4484 (the commit immediately preceding this PR's two commits — the repo is shallow-cloned so origin/dev...HEAD has no merge base, but the changed files match exactly).

Finding: the diagram's "submits payment" arrow now points at the wrong box

src/diagrams/AutoPayFlowDiagram.tsx — the AutoPay box (line 80) and the arrows that terminate on it (lines 92, 104).

Before this PR, the diagram had two accent boxes: Ottu Connect (Commits the transaction) and AutoPay (Creates the subscription). Two separate arrows fed them: the merchant's checkout call · auto_pay went into Connect, and the customer's submits payment (the CIT) also went into Connect — matching the removed accuracy-note comment that said "AutoPay never touches cardholder data. The CIT charge is processed by Ottu Connect."

This PR collapses the two boxes into one, labeled AutoPay, to stop disclosing the internal Connect→AutoPay hop — correct per the PR's own goal. But both arrows now terminate on that single box:

  • Line 92: checkout call · auto_pay → ends at (330, 236), inside the AutoPay rect (x 330–550, y 200–290, line 80).
  • Line 104: submits payment → ends at (552, 212), also inside/touching that same rect.

So the diagram now visually claims the customer's card payment is submitted directly to AutoPay, and that the merchant's checkout call goes to AutoPay rather than through the checkout/Connect layer. That's not a topology detail being hidden — it's a new factual claim, and it's the one thing the deleted comment explicitly said was false ("AutoPay never touches cardholder data"). Merging the boxes was the right call for hiding internal routing, but the box that survived still carries a specific label ("AutoPay / Creates the subscription") and both flows now read as going to that labeled entity.

Suggested fix (either works):

  • Re-route the submits payment arrow to end at the "Ottu Platform" container boundary (the dashed box, line 62) rather than the AutoPay rect specifically, so it doesn't visually attribute card processing to AutoPay, or
  • Keep two boxes but give the first a generic label (e.g. "Ottu Platform" or "Checkout") instead of removing it — satisfies "no internal service names" without merging distinct responsibilities into one.

The <desc>/alt text (lines 28, 117) don't have this problem — they only say "AutoPay creates the subscription synchronously," which is accurate and doesn't mention card processing.

Fix this →

Everything else checks out

  • Auth/path correction — every Bearer/jwt/Merchant-Id reference is gone from the mdx (verified via grep); all six endpoints now show Authorization: Api-Key <YOUR_API_KEY> against /b/pbl/v2/subscriptions/..., matching the PR's stated live verification.
  • Retrieve-response fields — the added fields (setup_session_id, amount_variability, cycle_interval_days, total_cycles, cancellation_initiator/reason/note, description) sit in valid JSON with correct comma placement.
  • New :::note replacing the two :::warning blocks — appropriate admonition choice per the root CLAUDE.md convention (:::note for clarifications vs. :::warning for gotchas), since there's no longer anything to warn about.
  • Anchor integrity — the new note links #customer-self-service-page, which exists at line 424 of the mdx (#### Customer Self-Service Page {#customer-self-service-page}); #step-by-step is unchanged.
  • Topology disclosures — confirmed removed from body text, workflow steps, and the diagram's <desc>/alt, matching the PR description.
  • Diagram box/arrow geometry otherwise stays within the "Ottu Platform" container and doesn't overlap the "Handled for you" box.

Not verified

I wasn't able to run npm run typecheck / npm run build myself — Bash execution required interactive approval in this environment and none was available. The PR description states both passed locally; the static diff review above doesn't contradict that (no syntax issues found in either file).
· branch epic/158909

…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
@ankitottu
ankitottu merged commit fb230bd into devAug 13, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@ankitottu
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

158910 :: fix: correct merchant API auth, and stop disclosing internal topology - #170

Merged
ankitottu merged 3 commits into
devfrom
epic/158909
Aug 13, 2026
Merged

158910 :: fix: correct merchant API auth, and stop disclosing internal topology#170
ankitottu merged 3 commits into
devfrom
epic/158909

Conversation

@ankitottu

Copy link
Copy Markdown
Contributor

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-Id header, and carried a warning that the JWT flow "isn't documented yet".

None of that is true for a merchant. Verified live on betabulk:

Api-Key -> 200
no auth -> 401
Merchant-Id omitted -> 200
BeforeAfter
Path.../subscriptions/.../b/pbl/v2/subscriptions/
CredentialAuthorization: Bearer <jwt_token>Authorization: Api-Key <YOUR_API_KEY>
Extra headerMerchant-Id: requirednot needed — removed
Warning block"Getting the JWT isn't documented yet"deleted; there is no JWT

Also 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:

  • "You never talk to AutoPay directly … Connect resolves your merchant from the API key and forwards the call"
  • "reach AutoPay through Ottu Connect at …"
  • Workflow step 2: "Ottu Connect commits and calls AutoPay synchronously …"
  • The flow diagram — two boxes, Ottu Connect / Commits the transactionAutoPay / Creates the subscription, with an internal creates subscription · sync arrow between them. Now one AutoPay box; the ongoing box reads Handled for you rather than "Owned by AutoPay".
  • The <desc> and alt text — 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 SURFACE note in the diagram source so the topology does not get reintroduced by a future edit.

Verification

POST /b/pbl/v2/subscriptions/ 200
GET /b/pbl/v2/subscriptions/{id}/ 200
GET /b/pbl/v2/subscriptions/{id}/cycles/ 200
  • npm run typecheck ✅ · npm run build
  • 0 matches for Ottu Connect / forwards the call / talk to AutoPay across both pages, the diagram source, and the served HTML
  • 0 matches for Bearer / jwt / Merchant-Id; retry_window_days gone
  • All 20 business-page images resolve
  • Diagram checked in Chrome in light and dark mode

⚠️ Still open

page-link 404s through the proxy. Five path spellings tried, and there is no page_url on 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.

cancel and regenerate-page-token are 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 lists retry_window_days, which was dropped in migrations/0028_drop_retry_window_days.py.

Do not merge until reviewed.

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

Copy link
Copy Markdown
ContributorAuthor

@claude review

@claude

claudeBot commented Aug 13, 2026

Copy link
Copy Markdown

Claude finished @ankitottu's task in 2m 58s —— View job


Review of PR #170

  • Gather context (diff, changed files, CLAUDE.md)
  • Review docs/developers/payments/autopay/index.mdx
  • Review src/diagrams/AutoPayFlowDiagram.tsx
  • Check verification claims (auth path, removed disclosures)
  • Post review feedback

Diffed both files against 34e4484 (the commit immediately preceding this PR's two commits — the repo is shallow-cloned so origin/dev...HEAD has no merge base, but the changed files match exactly).

Finding: the diagram's "submits payment" arrow now points at the wrong box

src/diagrams/AutoPayFlowDiagram.tsx — the AutoPay box (line 80) and the arrows that terminate on it (lines 92, 104).

Before this PR, the diagram had two accent boxes: Ottu Connect (Commits the transaction) and AutoPay (Creates the subscription). Two separate arrows fed them: the merchant's checkout call · auto_pay went into Connect, and the customer's submits payment (the CIT) also went into Connect — matching the removed accuracy-note comment that said "AutoPay never touches cardholder data. The CIT charge is processed by Ottu Connect."

This PR collapses the two boxes into one, labeled AutoPay, to stop disclosing the internal Connect→AutoPay hop — correct per the PR's own goal. But both arrows now terminate on that single box:

  • Line 92: checkout call · auto_pay → ends at (330, 236), inside the AutoPay rect (x 330–550, y 200–290, line 80).
  • Line 104: submits payment → ends at (552, 212), also inside/touching that same rect.

So the diagram now visually claims the customer's card payment is submitted directly to AutoPay, and that the merchant's checkout call goes to AutoPay rather than through the checkout/Connect layer. That's not a topology detail being hidden — it's a new factual claim, and it's the one thing the deleted comment explicitly said was false ("AutoPay never touches cardholder data"). Merging the boxes was the right call for hiding internal routing, but the box that survived still carries a specific label ("AutoPay / Creates the subscription") and both flows now read as going to that labeled entity.

Suggested fix (either works):

  • Re-route the submits payment arrow to end at the "Ottu Platform" container boundary (the dashed box, line 62) rather than the AutoPay rect specifically, so it doesn't visually attribute card processing to AutoPay, or
  • Keep two boxes but give the first a generic label (e.g. "Ottu Platform" or "Checkout") instead of removing it — satisfies "no internal service names" without merging distinct responsibilities into one.

The <desc>/alt text (lines 28, 117) don't have this problem — they only say "AutoPay creates the subscription synchronously," which is accurate and doesn't mention card processing.

Fix this →

Everything else checks out

  • Auth/path correction — every Bearer/jwt/Merchant-Id reference is gone from the mdx (verified via grep); all six endpoints now show Authorization: Api-Key <YOUR_API_KEY> against /b/pbl/v2/subscriptions/..., matching the PR's stated live verification.
  • Retrieve-response fields — the added fields (setup_session_id, amount_variability, cycle_interval_days, total_cycles, cancellation_initiator/reason/note, description) sit in valid JSON with correct comma placement.
  • New :::note replacing the two :::warning blocks — appropriate admonition choice per the root CLAUDE.md convention (:::note for clarifications vs. :::warning for gotchas), since there's no longer anything to warn about.
  • Anchor integrity — the new note links #customer-self-service-page, which exists at line 424 of the mdx (#### Customer Self-Service Page {#customer-self-service-page}); #step-by-step is unchanged.
  • Topology disclosures — confirmed removed from body text, workflow steps, and the diagram's <desc>/alt, matching the PR description.
  • Diagram box/arrow geometry otherwise stays within the "Ottu Platform" container and doesn't overlap the "Handled for you" box.

Not verified

I wasn't able to run npm run typecheck / npm run build myself — Bash execution required interactive approval in this environment and none was available. The PR description states both passed locally; the static diff review above doesn't contradict that (no syntax issues found in either file).
· branch epic/158909

…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
@ankitottu
ankitottu merged commit fb230bd into devAug 13, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@ankitottu