Skip to content

docs(subscriptions): POST /api/subscriptions/card-on-file ($0 setup-mode session) - #280

Merged
sweetmantech merged 3 commits into
mainfrom
docs/1910-card-on-file
Jul 29, 2026
Merged

docs(subscriptions): POST /api/subscriptions/card-on-file ($0 setup-mode session)#280
sweetmantech merged 3 commits into
mainfrom
docs/1910-card-on-file

Conversation

@sweetmantech

@sweetmantech sweetmantech commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Documents POST /api/subscriptions/card-on-file ahead of the api implementation, so the route ships against a published contract.

The endpoint exposes the existing api/lib/stripe/createCardOnFileSession.ts helper over HTTP: a Stripe mode: "setup" checkout session that saves a payment method against the account's Stripe customer with no charge today and no subscription. It is what lets an account that later hits zero credits be auto-recharged instead of dead-ending.

Contract

Endpoint POST /api/subscriptions/card-on-file
Auth Privy bearer or x-api-key (same as POST /api/subscriptions/sessions)
Body { "successUrl": "https://..." } — required, must be a valid URL
200 { "id": "cs_...", "url": "https://checkout.stripe.com/..." } (flat, no data wrapper)
400 missing or invalid body
401 missing or invalid credentials
500 internal error

The account is always resolved from the credentials. accountId is never accepted from the caller, which is why this endpoint gets its own CreateCardOnFileSessionRequest schema (successUrl only) rather than reusing CreateSubscriptionSessionRequest. The response and error envelopes are reused from the sessions endpoint unchanged.

Changes

  • api-reference/openapi/accounts.json — new /api/subscriptions/card-on-file path plus the CreateCardOnFileSessionRequest schema; additive edits only, spec re-validated as parseable JSON
  • api-reference/subscriptions/card-on-file-create.mdx — frontmatter-only reference page
  • docs.json — registered in the Accounts > Billing group so the page lands in llms.txt

Merge order

Merge this before the api PR that implements the route (linked from that PR).

Part of recoupable/chat#1910

🤖 Generated with Claude Code


Summary by cubic

Documents POST /api/subscriptions/card-on-file, a $0 Stripe setup-mode Checkout session that saves a card for the authenticated account. Sets the public contract ahead of the API so apps can integrate; aligns with recoupable/chat#1910.

  • New Features

    • OpenAPI: added /api/subscriptions/card-on-file and CreateCardOnFileSessionRequest (successUrl only); reuses CreateSubscriptionSessionResponse and SubscriptionSessionErrorResponse.
    • Auth: bearerAuth (Privy) or apiKeyAuth; account is derived from credentials (no accountId).
    • Docs: added reference page and registered it under Billing navigation.
  • Bug Fixes

    • OpenAPI: made CreateSubscriptionSessionResponse.url description payment-neutral (“complete Checkout”).
    • Docs: tightened the endpoint description and added per-status error examples for 400, 401, and 500.

Written for commit 3a95ee8. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added an API endpoint to create a $0 checkout session for securely saving a payment method without initiating a subscription or charge.
    • Added request documentation, including the required success redirect URL and error responses.
  • Documentation

    • Added a dedicated API reference page for creating card-on-file sessions.
    • Added the page to the Accounts → Billing documentation navigation.

…ode session)

Documents the card-on-file endpoint that exposes the existing
createCardOnFileSession helper over HTTP: a Stripe `mode: "setup"`
checkout session that saves a payment method for the authenticated
account without charging anything or starting a subscription.

- adds the `/api/subscriptions/card-on-file` path to the accounts
  OpenAPI spec, mirroring `/api/subscriptions/sessions` and reusing its
  CreateSubscriptionSessionResponse and SubscriptionSessionErrorResponse
  schemas
- adds a CreateCardOnFileSessionRequest schema: `successUrl` only, since
  the route resolves the account from the credentials and never accepts
  `accountId` from the caller
- adds the frontmatter-only reference page and registers it in the
  Billing group of docs.json so it lands in llms.txt

Part of recoupable/chat#1910

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cursor

cursor Bot commented Jul 29, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The API documentation adds a card-on-file session endpoint, its required success URL request schema, a dedicated reference page, and a Billing navigation entry.

Changes

Card-on-file API

Layer / File(s) Summary
Card-on-file endpoint contract
api-reference/openapi/accounts.json
Adds POST /api/subscriptions/card-on-file, the CreateCardOnFileSessionRequest schema, and documented success and error responses.
API reference publishing
api-reference/subscriptions/card-on-file-create.mdx, docs.json
Adds the API reference page and places it under Accounts → Billing navigation.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: arpitgupta1214

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the new documented subscription endpoint and its setup-mode purpose.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/1910-card-on-file

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@api-reference/openapi/accounts.json`:
- Around line 816-825: Update the description of the shared
CreateSubscriptionSessionResponse.url field to use payment-neutral wording,
replacing language that instructs callers to complete a payment with wording
that instructs them to complete Checkout. Keep the schema reference and endpoint
response structure unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9fb01d06-9c31-4d1c-b746-ddafa1d943d8

📥 Commits

Reviewing files that changed from the base of the PR and between 96169e6 and 6fa718a.

📒 Files selected for processing (3)
  • api-reference/openapi/accounts.json
  • api-reference/subscriptions/card-on-file-create.mdx
  • docs.json

Comment thread api-reference/openapi/accounts.json

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 3 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread api-reference/openapi/accounts.json
The card-on-file endpoint reuses CreateSubscriptionSessionResponse, whose
`url` said "complete the payment" — contradictory for a $0 setup session.
Generalized to "complete Checkout", which is accurate for both endpoints.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread api-reference/openapi/accounts.json Outdated
},
"/api/subscriptions/card-on-file": {
"post": {
"description": "Create a $0 card-on-file checkout session for the authenticated account. The session runs in Stripe `setup` mode: it saves a payment method against the account's Stripe customer without charging anything today and without starting a subscription. Use it so an account that later runs out of credits can be auto-recharged instead of dead-ending. The account is always resolved from the credentials; `accountId` is never accepted from the caller. Returns a hosted checkout URL that the client should redirect to.",

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

KISS

  • actual: 4+ sentences.
  • required: 2-3 sentences. Concise.

@sweetmantech sweetmantech Jul 29, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 3a95ee8: cut from 5 sentences to 3 (324 chars), calibrated against the sibling subscriptions/sessions description (3 sentences / 204 chars) rather than an arbitrary target. Dropped the accountId-is-never-accepted restatement (the Authorizations section already covers it, and the sibling does not repeat it) and folded the "use it so..." sentence into the setup-mode one. Rendered result verified locally, screenshots in the verification comment.

…xamples

Review feedback: the endpoint description ran to five sentences. Cut to three,
matching the terseness of the sibling subscriptions/sessions entry.

Also add per-response examples for 400, 401 and 500. The shared error schema
carries a single field-level example, so every status tab rendered the same
400-style message; the 401 tab claimed "successUrl is required" for what is
actually an auth failure. Each example is now the string the route really
returns, captured from the api preview.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@sweetmantech

Copy link
Copy Markdown
Collaborator Author

Local verification (Mintlify dev server)

Ran npx mintlify@latest dev against this branch and walked the rendered page. Two things fixed in 3a95ee8 as a result: your KISS note, plus a rendering bug I found while testing.

Your review note: description was 5 sentences

Fixed. Cut to 3, calibrated against the nearest sibling (POST /api/subscriptions/sessions, 3 sentences / 204 chars) rather than an arbitrary target.

Sentences Chars
Before 5 510
After 3 324
Sibling subscriptions/sessions 3 204

What was cut: the sentence restating that accountId is never accepted from the caller (already conveyed by the Authorizations section, and the sibling does not repeat it either), and the standalone "Use it so..." sentence, folded into the setup mode sentence.

Found while testing: every error tab showed the same 400 message

The shared SubscriptionSessionErrorResponse schema carries one field-level example ("successUrl is required"), and Mintlify renders that under every status tab that references the schema. So the 401 tab claimed {"error": "successUrl is required"} for what is actually an auth failure, and 500 said the same. Screenshot 3 below is that bug.

Fixed by adding per-response examples on this endpoint's 400/401/500. Each string is what the route actually returns, captured by probing the api preview from api#797 rather than invented:

Status Documented example Verified against
400 successUrl must be a valid URL POST with {"successUrl":"not-a-url"}
401 Exactly one of x-api-key or Authorization must be provided POST with no credentials
500 Internal server error createCardOnFileSessionHandler.ts:37

Left the shared schema untouched on purpose, so this does not change how the sibling endpoint renders. Note for a follow-up: POST /api/subscriptions/sessions has the same defect and would benefit from the same treatment.

Results

# Check Result
1 accounts.json parses after edit PASS (valid JSON)
2 Diff stays additive PASS (+10 / -1; see note below)
3 Page renders at /api-reference/subscriptions/card-on-file-create PASS (shot 1)
4 Nav placement PASS, Accounts to Billing, directly after "Create Subscription Session", aria-current="page" when active (shot 4)
5 Endpoint bar PASS, POST /api/subscriptions/card-on-file with a working "Try it"
6 Request schema PASS, successUrl string<uri> required, description and example (shot 2)
7 Response schema PASS, 200 returns id and url, both required
8 Status tabs present PASS, 200 / 400 / 401 / 500 all documented and rendered
9 Status tabs show distinct, correct bodies was FAIL, now PASS (shots 3 then 4)
10 Description length was FAIL (5 sentences), now PASS (3)
11 Code samples generate PASS across cURL, JS fetch, PHP

Screenshots

1. Endpoint page as rendered

Endpoint page

2. Request body and 200 response schema

Body and response schema

3. The bug: 401 tab showing a 400 message

401 tab showing successUrl is required

4. After the fix: 3-sentence description, and 401 showing the real auth error

Fixed description and 401 example

Two notes on method

  • Mintlify does not hot-reload the OpenAPI spec. MDX changes reload, but spec edits need a dev-server restart. I initially "verified" the old text against a stale server; the numbers above are from a clean restart.
  • The first attempt at this edit reserialized the whole JSON (131 insertions for a 3-line change) because a json.load / json.dumps round-trip of accounts.json is not byte-identical. Reverted and redone as anchored text edits, which is why the diff is +10 / -1.

Part of recoupable/chat#1910. Merge order unchanged: this PR, then api#797, then marketing#60.

@sweetmantech
sweetmantech merged commit 5255df6 into main Jul 29, 2026
3 checks passed
Sign up for free to 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