Skip to content

refactor: split openapi.json into 5 domain-specific specs#121

Merged
sweetmantech merged 1 commit intomainfrom
refactor/split-openapi-spec
Apr 9, 2026
Merged

refactor: split openapi.json into 5 domain-specific specs#121
sweetmantech merged 1 commit intomainfrom
refactor/split-openapi-spec

Conversation

@sweetmantech
Copy link
Copy Markdown
Collaborator

@sweetmantech sweetmantech commented Apr 9, 2026

Summary

  • Split the monolithic 16K-line openapi.json into 5 domain files under api-reference/openapi/
  • Each MDX page's frontmatter updated to reference its domain file
  • No pages deleted, no navigation changes — just the OpenAPI source path

Domain Files

File Endpoints Schemas Size
accounts.json 18 38 85K
content.json 26 61 134K
releases.json 14 64 97K
research.json 39 87 110K
social.json 16 52 79K

What changed

  • 1 file deleted: api-reference/openapi.json (monolith)
  • 5 files created: api-reference/openapi/*.json (domain specs)
  • 113 MDX files: one-line frontmatter update each, e.g.:
    - openapi: 'GET /api/accounts/{id}'
    + openapi: "/api-reference/openapi/accounts.json GET /api/accounts/{id}"

Why this approach

Closed #98 which deleted all 90 MDX files and switched to auto-generated pages. This simpler approach:

  • Keeps all MDX files (no lost customization)
  • Keeps navigation unchanged
  • Each domain file is ~3K lines vs the 16K monolith
  • Faster for AI agents to read and edit

Test plan

  • Verify all pages render correctly on preview deployment
  • Spot-check endpoints from each domain file
  • Verify "Try it" playground works

🤖 Generated with Claude Code


Summary by cubic

Split the 16K-line openapi.json into five domain-specific specs and updated all API docs to point to the right spec. No navigation or page content changes.

  • Refactors
    • Deleted api-reference/openapi.json; added api-reference/openapi/{accounts,content,releases,research,social}.json.
    • Updated frontmatter in 113 MDX files to reference the domain spec (e.g., openapi: "/api-reference/openapi/accounts.json GET /api/accounts/{id}").
    • Kept all MDX pages and routes unchanged; only the OpenAPI source path moved.

Written for commit c597bcd. Summary will update on new commits.

Summary by CodeRabbit

  • Documentation
    • Restructured API documentation across 100+ endpoints to use modular OpenAPI specification references
    • Organized API specifications into separate documentation files for improved documentation structure and maintainability

Split the monolithic 16K-line openapi.json into 5 domain files matching
the navigation tabs:
- accounts.json (18 endpoints, 38 schemas)
- content.json (26 endpoints, 61 schemas)
- releases.json (14 endpoints, 64 schemas)
- research.json (39 endpoints, 87 schemas)
- social.json (16 endpoints, 52 schemas)

Each MDX page's frontmatter updated to reference its domain file.
No navigation or page structure changes — just the OpenAPI source path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 9, 2026

📝 Walkthrough

Walkthrough

This pull request splits the monolithic OpenAPI specification into domain-specific files (accounts, social, research, content, etc.) and updates all corresponding MDX documentation pages to reference these new specifications by prefixing their openapi frontmatter with the appropriate spec file path.

Changes

Cohort / File(s) Summary
OpenAPI Specification Files
api-reference/openapi/accounts.json, api-reference/openapi/social.json
Added comprehensive OpenAPI 3.1 spec documents defining account management, admin operations, organizational endpoints, and social/connector/scraper operations with full request/response schemas and security configurations.
Accounts API Documentation
api-reference/accounts/*, api-reference/notifications/create.mdx, api-reference/organizations/*, api-reference/pulses/*, api-reference/subscriptions/get.mdx, api-reference/workspaces/create.mdx
Updated frontmatter openapi field to reference /api-reference/openapi/accounts.json alongside the endpoint descriptor (e.g., /api-reference/openapi/accounts.json GET /api/accounts/{id}).
Admins API Documentation
api-reference/admins/*
Updated frontmatter openapi field to reference /api-reference/openapi/accounts.json for all admin endpoint pages.
Artists API Documentation
api-reference/artist/*, api-reference/artists/*, api-reference/segment/fans.mdx
Updated frontmatter openapi field to reference /api-reference/openapi/releases.json for artist-related endpoints.
Chat API Documentation
api-reference/chat/*
Updated frontmatter openapi field to reference /api-reference/openapi/research.json for all chat/messaging endpoints.
Research API Documentation
api-reference/research/*
Updated 28 research endpoint pages to reference /api-reference/openapi/research.json in frontmatter openapi field.
Social & Posts API Documentation
api-reference/posts/get.mdx, api-reference/post/comments.mdx, api-reference/social/posts.mdx, api-reference/social/scrape.mdx, api-reference/comments/get.mdx, api-reference/connectors/*, api-reference/instagram/*, api-reference/spotify/*, api-reference/apify/scraper.mdx, api-reference/x/*
Updated frontmatter openapi field to reference /api-reference/openapi/social.json for social, scraping, connector, and platform-specific endpoints.
Content API Documentation
api-reference/content/*, api-reference/content-agent/*, api-reference/sandboxes/*, api-reference/transcribe/audio.mdx, api-reference/image/generation.mdx, api-reference/songs/*
Updated frontmatter openapi field to reference /api-reference/openapi/content.json for content generation, sandbox, transcription, and analysis endpoints.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–25 minutes

Possibly related PRs

Poem

🐰 The scattered endpoints, once alone,
Now gather in their domain home!
Each spec a nest, each doc aligned,
Organization, order, peace of mind!
thump thump – the docs hop forward, neat and bright! 📚✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR addresses the core objective from issue #98 (split monolithic openapi.json into domain-specific specs) by creating 5 OpenAPI files; however, it does not fully meet the requirement to remove redundant frontmatter-only MDX files or update docs.json configuration as specified in the issue. Complete the refactoring by: (1) removing the 113 frontmatter-only MDX files now made redundant; (2) updating docs.json to use Mintlify's openapi.source + directory config for auto-generated pages; (3) verifying all endpoints still render correctly after these changes.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'refactor: split openapi.json into 5 domain-specific specs' clearly and concisely summarizes the main structural refactoring, which aligns with the primary objective of breaking up the monolithic OpenAPI specification.
Out of Scope Changes check ✅ Passed All changes are within scope: the PR splits the monolithic spec into 5 domain-specific files (not 9 as originally proposed, but a valid subset) and updates corresponding MDX frontmatter references. No unrelated changes are present.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/split-openapi-spec

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 and usage tips.

Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

No issues found across 119 files

Note: This PR contains a large number of files. During the trial, cubic reviews up to 50 files per PR. Paid plans get a higher limit.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🧹 Nitpick comments (2)
api-reference/instagram/comments.mdx (1)

3-3: Align openapi frontmatter format with repository guideline

The codebase systematically uses openapi: "/api-reference/openapi/{spec}.json METHOD /path" format across 113 API reference files, but the documented guideline specifies openapi: 'METHOD /path'. While Mintlify supports both formats and pages resolve correctly, this creates a discrepancy between the guideline and actual implementation. Either update the guideline to reflect the path-prefixed format or refactor files to follow the documented METHOD /path pattern for consistency.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api-reference/instagram/comments.mdx` at line 3, The frontmatter uses the
repository's path-prefixed format for the openapi key (openapi:
"/api-reference/openapi/social.json GET /api/instagram/comments") but the
guideline expects just the HTTP method and path; update the openapi frontmatter
value to the canonical format "GET /api/instagram/comments" (i.e., remove the
leading /api-reference/openapi/{spec}.json prefix) so the openapi key reads:
openapi: 'GET /api/instagram/comments'.
api-reference/content/validate.mdx (1)

3-3: Update repo guidance for API reference frontmatter format to include file path.

The format in line 3 is correct per Mintlify's official documentation (openapi: "<file-path> <METHOD> <path>"). However, the repo's coding guidelines state only openapi: 'METHOD /path', which is incomplete and caused this discrepancy. Update the guideline to: openapi: '<file-path> METHOD /path' to align with Mintlify's supported format and prevent future confusion.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api-reference/content/validate.mdx` at line 3, The repo guidance currently
suggests using frontmatter like openapi: 'METHOD /path' which is incomplete;
update the guidance and any examples to require the full Mintlify-supported
format openapi: '<file-path> METHOD /path' so frontmatter entries (e.g., the
openapi key in api-reference/content/validate.mdx) include the file path,
METHOD, and path; change the guideline text, update example snippets to the new
format, and run a quick repo-wide search for openapi frontmatter to correct any
other occurrences.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@api-reference/content/generate-video.mdx`:
- Line 3: The frontmatter key openapi in
api-reference/content/generate-video.mdx currently includes the spec file path
prefix; update the value to follow the repo convention by setting openapi to the
HTTP method and path only (e.g., openapi: 'POST /api/content/video') so it
matches the documented format used across the codebase.

In `@api-reference/openapi/accounts.json`:
- Around line 129-184: Add explicit OpenAPI security requirement objects to each
authenticated operation (PATCH /api/accounts, GET /api/organizations, POST
/api/workspaces, GET /api/pulses, PATCH /api/pulses, POST /api/notifications) so
they are not treated as public; for each operation (e.g., the "patch" operation
in accounts.json) add a "security" array referencing the already-declared
authentication schemes used by the API (the x-api-key and/or Authorization
Bearer scheme names defined in your components/securitySchemes) so code
generators and tools know these endpoints require credentials and can surface
401/403 responses correctly.
- Around line 1821-1835: The CreateAccountRequest schema currently allows an
empty object; enforce the "at least one of email or wallet" rule by updating the
CreateAccountRequest definition to include an anyOf constraint that requires
either "email" or "wallet" (reference the schema name CreateAccountRequest and
its properties "email" and "wallet"); add two anyOf branches each with a
required array (one with ["email"], one with ["wallet"]) so generated clients
and the playground will reject {} while keeping existing property definitions
intact.
- Around line 1494-1510: The OpenAPI 3.1 schema uses deprecated `nullable: true`
entries (e.g., properties "image", "instruction", "knowledges") which must be
converted to JSON Schema style nullable type arrays; for each property currently
using `nullable: true` (15 occurrences total) replace the `type: "X",
"nullable": true` pattern with `type: ["X","null"]` (e.g., `type:
["string","null"]` for "image"/"instruction" and `type: ["array","null"]` for
"knowledges"), ensuring any `items` refs remain intact and no other schema
keywords are removed.

In `@api-reference/openapi/social.json`:
- Around line 930-1099: The GET/POST/DELETE operations under the
"/api/connectors" path are missing operation-level security declarations; add a
security array to each operation (get, post, delete) referencing the existing
schemes (e.g., bearerAuth and/or apiKeyAuth) so these endpoints are not treated
as public—for each operation add "security": [{"bearerAuth": []}, {"apiKeyAuth":
[]}] (or the appropriate scheme combination) to enforce authentication.
- Around line 1127-1131: The OpenAPI 3.1 spec in social.json still uses
"nullable": true (e.g., the "error" property shown) which is invalid; locate
every property object containing "nullable": true (including the listed
instances) and remove "nullable": true, then replace or update the property's
"type" to the JSON-Schema union form by adding "null" (for example change a
string type to "type": ["string","null"] or an object/array/number type to
include null). Ensure you update each occurrence consistently (search for
"nullable": true), preserving existing type information in the property's schema
(for properties with no explicit "type", add the appropriate union type
including "null").

In `@api-reference/research/playlist.mdx`:
- Around line 1-4: The repo has mixed OpenAPI frontmatter formats (new style
like openapi: "/api-reference/openapi/research.json GET /api/research/playlist"
in playlist.mdx vs legacy "post /path" entries); scan all api-reference MDX
files for the old pattern (e.g., strings like "post /", "get /" used in
frontmatter) and either (A) convert them to the new frontmatter format matching
playlist.mdx (compose openapi value as "<openapi-json-path> <HTTP_METHOD>
</path>") or (B) confirm with Mintlify/maintainers that the legacy format is
supported and document that decision; update all affected files consistently and
run the docs build to verify the "Try it" playground and rendering work.

In `@api-reference/sandboxes/snapshot.mdx`:
- Around line 1-4: Update the OpenAPI frontmatter in snapshot.mdx by removing
the spec file path prefix so the openapi field contains only the method and
path; change the existing openapi value that currently reads
"/api-reference/openapi/content.json PATCH /api/sandboxes" to the short form
"PATCH /api/sandboxes" in the frontmatter block so it conforms to the API
reference guidelines.

---

Nitpick comments:
In `@api-reference/content/validate.mdx`:
- Line 3: The repo guidance currently suggests using frontmatter like openapi:
'METHOD /path' which is incomplete; update the guidance and any examples to
require the full Mintlify-supported format openapi: '<file-path> METHOD /path'
so frontmatter entries (e.g., the openapi key in
api-reference/content/validate.mdx) include the file path, METHOD, and path;
change the guideline text, update example snippets to the new format, and run a
quick repo-wide search for openapi frontmatter to correct any other occurrences.

In `@api-reference/instagram/comments.mdx`:
- Line 3: The frontmatter uses the repository's path-prefixed format for the
openapi key (openapi: "/api-reference/openapi/social.json GET
/api/instagram/comments") but the guideline expects just the HTTP method and
path; update the openapi frontmatter value to the canonical format "GET
/api/instagram/comments" (i.e., remove the leading
/api-reference/openapi/{spec}.json prefix) so the openapi key reads: openapi:
'GET /api/instagram/comments'.
🪄 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

Run ID: 8bcce0a5-22a0-45b1-919d-a79ce0b2a050

📥 Commits

Reviewing files that changed from the base of the PR and between 097a526 and c597bcd.

📒 Files selected for processing (119)
  • api-reference/accounts/add-artist.mdx
  • api-reference/accounts/create.mdx
  • api-reference/accounts/get.mdx
  • api-reference/accounts/id.mdx
  • api-reference/accounts/update.mdx
  • api-reference/admins/check.mdx
  • api-reference/admins/coding-agent-slack-tags.mdx
  • api-reference/admins/coding-pr.mdx
  • api-reference/admins/content-slack-tags.mdx
  • api-reference/admins/emails.mdx
  • api-reference/admins/privy.mdx
  • api-reference/admins/sandboxes-orgs.mdx
  • api-reference/admins/sandboxes.mdx
  • api-reference/apify/scraper.mdx
  • api-reference/artist/profile.mdx
  • api-reference/artist/segments.mdx
  • api-reference/artist/socials.mdx
  • api-reference/artists/create.mdx
  • api-reference/artists/list.mdx
  • api-reference/chat/artist.mdx
  • api-reference/chat/chats.mdx
  • api-reference/chat/compact.mdx
  • api-reference/chat/messages-copy.mdx
  • api-reference/chat/messages-trailing-delete.mdx
  • api-reference/chat/messages.mdx
  • api-reference/chat/segment.mdx
  • api-reference/comments/get.mdx
  • api-reference/connectors/authorize.mdx
  • api-reference/connectors/disconnect.mdx
  • api-reference/connectors/list.mdx
  • api-reference/content-agent/callback.mdx
  • api-reference/content-agent/webhook.mdx
  • api-reference/content/analyze-video.mdx
  • api-reference/content/create.mdx
  • api-reference/content/edit.mdx
  • api-reference/content/estimate.mdx
  • api-reference/content/generate-caption.mdx
  • api-reference/content/generate-image.mdx
  • api-reference/content/generate-video.mdx
  • api-reference/content/template-detail.mdx
  • api-reference/content/templates.mdx
  • api-reference/content/transcribe-audio.mdx
  • api-reference/content/upscale.mdx
  • api-reference/content/validate.mdx
  • api-reference/fans/get.mdx
  • api-reference/image/generation.mdx
  • api-reference/instagram/comments.mdx
  • api-reference/instagram/profiles.mdx
  • api-reference/notifications/create.mdx
  • api-reference/openapi.json
  • api-reference/openapi/accounts.json
  • api-reference/openapi/content.json
  • api-reference/openapi/releases.json
  • api-reference/openapi/research.json
  • api-reference/openapi/social.json
  • api-reference/organizations/add-artist.mdx
  • api-reference/organizations/create.mdx
  • api-reference/organizations/list.mdx
  • api-reference/post/comments.mdx
  • api-reference/posts/get.mdx
  • api-reference/pulses/list.mdx
  • api-reference/pulses/update.mdx
  • api-reference/research/albums.mdx
  • api-reference/research/audience.mdx
  • api-reference/research/career.mdx
  • api-reference/research/charts.mdx
  • api-reference/research/cities.mdx
  • api-reference/research/curator.mdx
  • api-reference/research/deep.mdx
  • api-reference/research/discover.mdx
  • api-reference/research/enrich.mdx
  • api-reference/research/extract.mdx
  • api-reference/research/festivals.mdx
  • api-reference/research/genres.mdx
  • api-reference/research/insights.mdx
  • api-reference/research/instagram-posts.mdx
  • api-reference/research/lookup.mdx
  • api-reference/research/metrics.mdx
  • api-reference/research/milestones.mdx
  • api-reference/research/people.mdx
  • api-reference/research/playlist.mdx
  • api-reference/research/playlists.mdx
  • api-reference/research/profile.mdx
  • api-reference/research/radio.mdx
  • api-reference/research/rank.mdx
  • api-reference/research/search.mdx
  • api-reference/research/similar.mdx
  • api-reference/research/track.mdx
  • api-reference/research/tracks.mdx
  • api-reference/research/urls.mdx
  • api-reference/research/venues.mdx
  • api-reference/research/web.mdx
  • api-reference/sandboxes/create.mdx
  • api-reference/sandboxes/delete.mdx
  • api-reference/sandboxes/file.mdx
  • api-reference/sandboxes/list.mdx
  • api-reference/sandboxes/setup.mdx
  • api-reference/sandboxes/snapshot.mdx
  • api-reference/sandboxes/upload.mdx
  • api-reference/segment/fans.mdx
  • api-reference/social/posts.mdx
  • api-reference/social/scrape.mdx
  • api-reference/songs/analyze-presets.mdx
  • api-reference/songs/analyze.mdx
  • api-reference/spotify/album.mdx
  • api-reference/spotify/artist-albums.mdx
  • api-reference/spotify/artist-top-tracks.mdx
  • api-reference/spotify/artist.mdx
  • api-reference/spotify/search.mdx
  • api-reference/subscriptions/get.mdx
  • api-reference/tasks/create.mdx
  • api-reference/tasks/delete.mdx
  • api-reference/tasks/get.mdx
  • api-reference/tasks/runs.mdx
  • api-reference/tasks/update.mdx
  • api-reference/transcribe/audio.mdx
  • api-reference/workspaces/create.mdx
  • api-reference/x/search.mdx
  • api-reference/x/trends.mdx

---
title: 'Generate Video'
openapi: 'POST /api/content/video'
openapi: "/api-reference/openapi/content.json POST /api/content/video"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify that each path-prefixed openapi frontmatter entry resolves to an existing operation.
python - <<'PY'
import json, pathlib, re, sys

errors = []
for mdx in pathlib.Path("api-reference").rglob("*.mdx"):
    text = mdx.read_text(encoding="utf-8")
    m = re.search(r'^openapi:\s*["\'](.+?)["\']\s*$', text, re.M)
    if not m:
        continue
    value = m.group(1).strip()
    if not value.startswith("/api-reference/openapi/"):
        continue
    parts = value.split(" ", 2)
    if len(parts) != 3:
        errors.append(f"{mdx}: malformed openapi value: {value}")
        continue
    spec_path, method, route = parts
    spec_file = pathlib.Path(spec_path.lstrip("/"))
    if not spec_file.exists():
        errors.append(f"{mdx}: missing spec file {spec_file}")
        continue
    spec = json.loads(spec_file.read_text(encoding="utf-8"))
    op = spec.get("paths", {}).get(route, {}).get(method.lower())
    if op is None:
        errors.append(f"{mdx}: operation not found in {spec_file}: {method} {route}")

if errors:
    print("\n".join(errors))
    sys.exit(1)

print("All path-prefixed openapi references resolve to existing operations.")
PY

Repository: recoupable/docs

Length of output: 127


🌐 Web query:

Mintlify docs: Is openapi: "/api-reference/openapi/.json METHOD /path"a supported API reference MDX frontmatter format, or should it remainopenapi: "METHOD /path"when usingopenapi.source+directory in docs config?

💡 Result:

Yes—Mintlify supports prefixing the operation with an OpenAPI file path in MDX frontmatter:

  • Supported: openapi: "/path/to/spec.json GET /users" (useful when you have multiple specs or need to disambiguate). [1]
  • Also supported: openapi: "GET /endpoint" (when Mintlify can resolve the operation against the default/available spec context). [2]

Using api.openapi in docs.json (including the { source, directory } form) defines what specs are available, but it doesn’t make the “<spec>.json METHOD /path” form invalid—include the spec path when you need to target a specific spec; otherwise keep it as METHOD /path. [1] [3]


Update openapi frontmatter format to match repo convention

The current format openapi: "/api-reference/openapi/content.json POST /api/content/video" works and references resolve correctly, but it deviates from the established repo guideline requiring openapi: 'METHOD /path' (without the spec file path prefix). Standardize to the documented format to maintain consistency across the codebase.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api-reference/content/generate-video.mdx` at line 3, The frontmatter key
openapi in api-reference/content/generate-video.mdx currently includes the spec
file path prefix; update the value to follow the repo convention by setting
openapi to the HTTP method and path only (e.g., openapi: 'POST
/api/content/video') so it matches the documented format used across the
codebase.

Comment on lines +129 to +184
"patch": {
"description": "Update an existing account's profile information including name, organization, image, instruction, job title, role type, company name, and knowledges. Requires authentication via x-api-key or Authorization Bearer token. The authenticated account may update itself or a permitted account_id override.",
"requestBody": {
"description": "Account fields to update",
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateAccountRequest"
}
}
}
},
"responses": {
"200": {
"description": "Account updated successfully",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AccountDataResponse"
}
}
}
},
"400": {
"description": "Bad request - account not found or update failed",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AccountErrorResponse"
}
}
}
},
"401": {
"description": "Unauthorized - missing or invalid credentials",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AccountErrorResponse"
}
}
}
},
"403": {
"description": "Forbidden - account override not permitted",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AccountErrorResponse"
}
}
}
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's check if the file exists and get basic info
ls -la api-reference/openapi/accounts.json
wc -l api-reference/openapi/accounts.json

Repository: recoupable/docs

Length of output: 185


🏁 Script executed:

# Check the OpenAPI version declaration
head -20 api-reference/openapi/accounts.json

Repository: recoupable/docs

Length of output: 622


🏁 Script executed:

# Check if securitySchemes is defined
rg "securitySchemes" api-reference/openapi/accounts.json -A 10

Repository: recoupable/docs

Length of output: 356


🏁 Script executed:

# Look at the lines mentioned in the review (129-184, 224-280, 418-474, 476-592, 594-650)
sed -n '129,184p' api-reference/openapi/accounts.json

Repository: recoupable/docs

Length of output: 1993


🏁 Script executed:

# Check lines 224-280
sed -n '224,280p' api-reference/openapi/accounts.json

Repository: recoupable/docs

Length of output: 2044


🏁 Script executed:

# Check if the operations have security declarations anywhere
rg '"security"' api-reference/openapi/accounts.json -B 2 -A 2

Repository: recoupable/docs

Length of output: 2116


🏁 Script executed:

# Check lines 418-474
sed -n '418,474p' api-reference/openapi/accounts.json | head -80

Repository: recoupable/docs

Length of output: 1757


🏁 Script executed:

# Check lines 476-592 (partial - this is a large range)
sed -n '476,530p' api-reference/openapi/accounts.json | head -80

Repository: recoupable/docs

Length of output: 2026


🏁 Script executed:

# Check for the POST /api/workspaces, /api/pulses, and /api/notifications operations
rg '"/api/workspaces"|"/api/pulses"|"/api/notifications"' api-reference/openapi/accounts.json -B 2 -A 50 | head -150

Repository: recoupable/docs

Length of output: 5096


🏁 Script executed:

# Check if there's a POST /api/pulses operation
rg '"/api/pulses"' api-reference/openapi/accounts.json -A 100 | grep -E '"(post|get|put|delete|patch)"' | head -20

Repository: recoupable/docs

Length of output: 90


🏁 Script executed:

# Look for POST /api/pulses more specifically
sed -n '550,650p' api-reference/openapi/accounts.json | head -100

Repository: recoupable/docs

Length of output: 3181


🏁 Script executed:

# Check if any of the identified operations have security declarations
rg -A 30 '"/api/accounts/{id}"' api-reference/openapi/accounts.json | grep -E '"(patch|get|put|delete)"' -A 30 | head -60

Repository: recoupable/docs

Length of output: 177


🏁 Script executed:

# Search more carefully for security declarations in the operations mentioned
for op in 'PATCH /api/accounts' 'GET /api/organizations' 'POST /api/workspaces' 'GET /api/pulses' 'PATCH /api/pulses' 'POST /api/notifications'; do
  echo "=== Checking $op ==="
  rg '"security"' api-reference/openapi/accounts.json -B 10 | grep -E '(patch|get|post)"|security"' | head -5
done

Repository: recoupable/docs

Length of output: 816


🏁 Script executed:

# Let me check each operation more systematically - look at PATCH /api/accounts with context
sed -n '125,190p' api-reference/openapi/accounts.json | grep -E '"security"|"patch"|"get"|"post"'

Repository: recoupable/docs

Length of output: 91


🏁 Script executed:

# Check GET /api/organizations
sed -n '220,285p' api-reference/openapi/accounts.json | grep -E '"security"|"patch"|"get"|"post"'

Repository: recoupable/docs

Length of output: 89


🏁 Script executed:

# Check POST /api/workspaces
sed -n '410,480p' api-reference/openapi/accounts.json | grep -E '"security"|"patch"|"get"|"post"'

Repository: recoupable/docs

Length of output: 89


🏁 Script executed:

# Check GET /api/pulses
sed -n '470,540p' api-reference/openapi/accounts.json | grep -E '"security"|"patch"|"get"|"post"'

Repository: recoupable/docs

Length of output: 73


🏁 Script executed:

# Check PATCH /api/pulses
sed -n '530,600p' api-reference/openapi/accounts.json | grep -E '"security"|"patch"|"get"|"post"'

Repository: recoupable/docs

Length of output: 91


🏁 Script executed:

# Check POST /api/notifications
sed -n '585,660p' api-reference/openapi/accounts.json | grep -E '"security"|"patch"|"get"|"post"'

Repository: recoupable/docs

Length of output: 111


🏁 Script executed:

# Let me get the full structure for PATCH /api/accounts with better context
sed -n '129,165p' api-reference/openapi/accounts.json

Repository: recoupable/docs

Length of output: 1469


🏁 Script executed:

# Get full structure for GET /api/organizations
sed -n '224,260p' api-reference/openapi/accounts.json

Repository: recoupable/docs

Length of output: 1375


🏁 Script executed:

# Get full structure for POST /api/workspaces
sed -n '418,450p' api-reference/openapi/accounts.json

Repository: recoupable/docs

Length of output: 1114


🏁 Script executed:

# Get full structure for GET /api/pulses
sed -n '476,510p' api-reference/openapi/accounts.json

Repository: recoupable/docs

Length of output: 1437


🏁 Script executed:

# Get full structure for PATCH /api/pulses
sed -n '540,575p' api-reference/openapi/accounts.json

Repository: recoupable/docs

Length of output: 1153


🏁 Script executed:

# Get full structure for POST /api/notifications
sed -n '594,630p' api-reference/openapi/accounts.json

Repository: recoupable/docs

Length of output: 1511


Add security declarations to authenticated operations that lack them.

PATCH /api/accounts, GET /api/organizations, POST /api/workspaces, GET /api/pulses, PATCH /api/pulses, and POST /api/notifications all describe authentication requirements and return 401/403 responses but none declare security. Without these declarations, OpenAPI tools and code generators will treat these operations as public endpoints.

Fix pattern
       "patch": {
+        "security": [
+          { "apiKeyAuth": [] },
+          { "bearerAuth": [] }
+        ],
         "description": "Update an existing account's profile information including name, organization, image, instruction, job title, role type, company name, and knowledges. Requires authentication via x-api-key or Authorization Bearer token. The authenticated account may update itself or a permitted account_id override.",

Apply to all six operations.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"patch": {
"description": "Update an existing account's profile information including name, organization, image, instruction, job title, role type, company name, and knowledges. Requires authentication via x-api-key or Authorization Bearer token. The authenticated account may update itself or a permitted account_id override.",
"requestBody": {
"description": "Account fields to update",
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateAccountRequest"
}
}
}
},
"responses": {
"200": {
"description": "Account updated successfully",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AccountDataResponse"
}
}
}
},
"400": {
"description": "Bad request - account not found or update failed",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AccountErrorResponse"
}
}
}
},
"401": {
"description": "Unauthorized - missing or invalid credentials",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AccountErrorResponse"
}
}
}
},
"403": {
"description": "Forbidden - account override not permitted",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AccountErrorResponse"
}
}
}
}
}
}
"patch": {
"security": [
{ "apiKeyAuth": [] },
{ "bearerAuth": [] }
],
"description": "Update an existing account's profile information including name, organization, image, instruction, job title, role type, company name, and knowledges. Requires authentication via x-api-key or Authorization Bearer token. The authenticated account may update itself or a permitted account_id override.",
"requestBody": {
"description": "Account fields to update",
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateAccountRequest"
}
}
}
},
"responses": {
"200": {
"description": "Account updated successfully",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AccountDataResponse"
}
}
}
},
"400": {
"description": "Bad request - account not found or update failed",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AccountErrorResponse"
}
}
}
},
"401": {
"description": "Unauthorized - missing or invalid credentials",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AccountErrorResponse"
}
}
}
},
"403": {
"description": "Forbidden - account override not permitted",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AccountErrorResponse"
}
}
}
}
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api-reference/openapi/accounts.json` around lines 129 - 184, Add explicit
OpenAPI security requirement objects to each authenticated operation (PATCH
/api/accounts, GET /api/organizations, POST /api/workspaces, GET /api/pulses,
PATCH /api/pulses, POST /api/notifications) so they are not treated as public;
for each operation (e.g., the "patch" operation in accounts.json) add a
"security" array referencing the already-declared authentication schemes used by
the API (the x-api-key and/or Authorization Bearer scheme names defined in your
components/securitySchemes) so code generators and tools know these endpoints
require credentials and can surface 401/403 responses correctly.

Comment on lines +1494 to +1510
"image": {
"type": "string",
"nullable": true,
"description": "Profile image URL"
},
"instruction": {
"type": "string",
"nullable": true,
"description": "Custom AI instructions for this account"
},
"knowledges": {
"type": "array",
"nullable": true,
"items": {
"$ref": "#/components/schemas/Knowledge"
},
"description": "Knowledge base files attached to this account"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, let's check if the file exists and its basic properties
if [ -f "api-reference/openapi/accounts.json" ]; then
  # Check file size and first few lines to see OpenAPI version
  echo "=== File exists. Checking OpenAPI version declaration ==="
  head -20 api-reference/openapi/accounts.json
else
  echo "File not found at api-reference/openapi/accounts.json"
  # Try to find the file
  find . -name "accounts.json" -type f 2>/dev/null | head -5
fi

Repository: recoupable/docs

Length of output: 680


🏁 Script executed:

#!/bin/bash
# Check the specific lines mentioned in the review
if [ -f "api-reference/openapi/accounts.json" ]; then
  echo "=== Lines 1494-1510 ==="
  sed -n '1494,1510p' api-reference/openapi/accounts.json
fi

Repository: recoupable/docs

Length of output: 645


🏁 Script executed:

#!/bin/bash
# Count total occurrences of "nullable" in the file
if [ -f "api-reference/openapi/accounts.json" ]; then
  echo "=== Total nullable occurrences ==="
  grep -c '"nullable"' api-reference/openapi/accounts.json
  
  echo -e "\n=== Sample nullable usages (first 10) ==="
  grep -n '"nullable"' api-reference/openapi/accounts.json | head -10
fi

Repository: recoupable/docs

Length of output: 494


🌐 Web query:

OpenAPI 3.1 nullable keyword deprecated JSON Schema type array

💡 Result:

In OpenAPI 3.1, the nullable keyword from OAS 3.0.x is no longer used/supported because OAS 3.1 aligns schemas with JSON Schema 2020-12; instead, you express “nullable” by allowing the JSON value null in the schema itself (e.g., via a multi-type). [1][2]

In JSON Schema (2020-12), the type keyword can be either:

  • a string, or
  • a non-empty array of strings (multi-type), which is what you use to include "null". [3]

Examples (OAS 3.1):

# string OR null
type: [string, "null"]
# object OR null
type: [object, "null"]
properties:
  id: { type: integer }

(Equivalent alternatives include anyOf/oneOf with { "type": "null" }.) [1][3]

Sources:
[1] OpenAPI Initiative – OpenAPI 3.1 announcement (nullable removed; use type arrays incl. null) (openapis.org)
[2] OpenAPI Spec v3.1.0 – Schema Object is a superset of JSON Schema Draft 2020-12 (spec.openapis.org)
[3] JSON Schema Validation (2020-12) – type can be a string or an array of strings (learnjsonschema.com)

Citations:


Replace nullable: true with JSON Schema type arrays for OpenAPI 3.1 compliance.

This document declares OpenAPI 3.1.0, but uses the deprecated 3.0-style nullable keyword. OpenAPI 3.1 aligns with JSON Schema 2020-12, which does not support nullable. Null types must be expressed as type arrays: type: ["string", "null"], type: ["array", "null"], etc. There are 15 instances of nullable throughout the file requiring conversion for spec compliance.

Example conversion
           "image": {
-            "type": "string",
-            "nullable": true,
+            "type": [
+              "string",
+              "null"
+            ],
             "description": "Profile image URL"
           },

Apply the same conversion pattern to all 15 nullable occurrences.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"image": {
"type": "string",
"nullable": true,
"description": "Profile image URL"
},
"instruction": {
"type": "string",
"nullable": true,
"description": "Custom AI instructions for this account"
},
"knowledges": {
"type": "array",
"nullable": true,
"items": {
"$ref": "#/components/schemas/Knowledge"
},
"description": "Knowledge base files attached to this account"
"image": {
"type": [
"string",
"null"
],
"description": "Profile image URL"
},
"instruction": {
"type": "string",
"nullable": true,
"description": "Custom AI instructions for this account"
},
"knowledges": {
"type": "array",
"nullable": true,
"items": {
"$ref": "#/components/schemas/Knowledge"
},
"description": "Knowledge base files attached to this account"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api-reference/openapi/accounts.json` around lines 1494 - 1510, The OpenAPI
3.1 schema uses deprecated `nullable: true` entries (e.g., properties "image",
"instruction", "knowledges") which must be converted to JSON Schema style
nullable type arrays; for each property currently using `nullable: true` (15
occurrences total) replace the `type: "X", "nullable": true` pattern with `type:
["X","null"]` (e.g., `type: ["string","null"]` for "image"/"instruction" and
`type: ["array","null"]` for "knowledges"), ensuring any `items` refs remain
intact and no other schema keywords are removed.

Comment on lines +1821 to +1835
"CreateAccountRequest": {
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email",
"description": "Email address to associate with the account. If an account with this email exists, it will be returned."
},
"wallet": {
"type": "string",
"description": "Wallet address to associate with the account. If an account with this wallet exists, it will be returned."
}
},
"description": "At least one of email or wallet should be provided to identify or create an account."
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

fd -e json api-reference

Repository: recoupable/docs

Length of output: 41


🏁 Script executed:

git ls-files | grep -i accounts

Repository: recoupable/docs

Length of output: 261


🏁 Script executed:

wc -l api-reference/openapi/accounts.json

Repository: recoupable/docs

Length of output: 99


🏁 Script executed:

sed -n '1821,1835p' api-reference/openapi/accounts.json

Repository: recoupable/docs

Length of output: 697


🏁 Script executed:

web_search
Query: OpenAPI JSON Schema anyOf required pattern "at least one field required"

Repository: recoupable/docs

Length of output: 154


🌐 Web query:

OpenAPI JSON Schema anyOf required pattern "at least one field required"

💡 Result:

To express “at least one field is required” in an OpenAPI schema, use anyOf with required lists—each option requires one of the fields. anyOf means the instance must validate against at least one of the subschemas. [1][2]

OpenAPI 3.0 / 3.1 example (at least one of email or id)

type: object
properties:
  id:
    type: string
  email:
    type: string
    format: email
anyOf:
  - required: [id]
  - required: [email]

More fields (at least one of many)

anyOf:
  - required: [a]
  - required: [b]
  - required: [c]

Notes:

  • In OAS 3.0, the Schema Object is an extended subset of JSON Schema, but anyOf and required are supported and commonly used for this pattern. [3]
  • If you want a human-friendly validation message like “at least one field required”, that’s typically produced by your validator/tooling; JSON Schema/OpenAPI itself doesn’t standardize custom error text.

Sources:
[1] https://tour.json-schema.org/content/06-Combining-Subschemas/05-Valid-Against-anyOf-the-Subschemas%28OR%29
[2] https://www.learnjsonschema.com/draft6/validation/anyof/
[3] https://spec.openapis.org/oas/v3.0.4.html


Enforce "at least one of email or wallet" constraint in the schema.

The description correctly states at least one field must be present, but the schema currently allows an empty object {}. This inconsistency causes generated clients and the playground to accept invalid requests that don't match the documented contract.

Use anyOf with required constraints to enforce the rule:

Suggested schema constraint
      "CreateAccountRequest": {
        "type": "object",
+       "anyOf": [
+         { "required": ["email"] },
+         { "required": ["wallet"] }
+       ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"CreateAccountRequest": {
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email",
"description": "Email address to associate with the account. If an account with this email exists, it will be returned."
},
"wallet": {
"type": "string",
"description": "Wallet address to associate with the account. If an account with this wallet exists, it will be returned."
}
},
"description": "At least one of email or wallet should be provided to identify or create an account."
},
"CreateAccountRequest": {
"type": "object",
"anyOf": [
{ "required": ["email"] },
{ "required": ["wallet"] }
],
"properties": {
"email": {
"type": "string",
"format": "email",
"description": "Email address to associate with the account. If an account with this email exists, it will be returned."
},
"wallet": {
"type": "string",
"description": "Wallet address to associate with the account. If an account with this wallet exists, it will be returned."
}
},
"description": "At least one of email or wallet should be provided to identify or create an account."
},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api-reference/openapi/accounts.json` around lines 1821 - 1835, The
CreateAccountRequest schema currently allows an empty object; enforce the "at
least one of email or wallet" rule by updating the CreateAccountRequest
definition to include an anyOf constraint that requires either "email" or
"wallet" (reference the schema name CreateAccountRequest and its properties
"email" and "wallet"); add two anyOf branches each with a required array (one
with ["email"], one with ["wallet"]) so generated clients and the playground
will reject {} while keeping existing property definitions intact.

Comment on lines +930 to +1099
"/api/connectors": {
"get": {
"description": "List available connectors and their connection status. Returns all supported third-party integrations (e.g., Google Sheets, TikTok) along with whether they are currently connected.",
"parameters": [
{
"name": "account_id",
"in": "query",
"description": "Optional account ID to get connectors for a different account (e.g., an artist, workspace, or organization). The authenticated account must have access to the specified account. Omit to get your own account's connectors.",
"required": false,
"schema": {
"type": "string",
"format": "uuid"
}
}
],
"responses": {
"200": {
"description": "Connectors retrieved successfully",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ConnectorsResponse"
}
}
}
},
"400": {
"description": "Bad request - invalid account_id format",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Unauthorized - invalid or missing API key",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Forbidden - no access to the specified account",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
},
"delete": {
"description": "Disconnect a connected account from a third-party service. This revokes the OAuth connection and removes stored credentials.",
"requestBody": {
"description": "Connection to disconnect",
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DisconnectConnectorRequest"
}
}
}
},
"responses": {
"200": {
"description": "Connector disconnected successfully",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DisconnectConnectorResponse"
}
}
}
},
"400": {
"description": "Bad request - missing or invalid parameters",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Unauthorized - invalid or missing API key",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Forbidden - no access to the specified account or connection",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
},
"post": {
"description": "Generate an OAuth authorization URL for connecting a third-party service. Redirect to the returned URL to complete the OAuth flow.",
"requestBody": {
"description": "Authorization request details",
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthorizeConnectorRequest"
}
}
}
},
"responses": {
"200": {
"description": "Authorization URL generated successfully",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthorizeConnectorResponse"
}
}
}
},
"400": {
"description": "Bad request - invalid connector or parameters",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Unauthorized - invalid or missing API key",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Forbidden - no access to the specified account",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the social.json file structure and confirm the security issue
cat -n api-reference/openapi/social.json | head -100

Repository: recoupable/docs

Length of output: 3836


🏁 Script executed:

# Get the size of the file to understand how to read it efficiently
wc -l api-reference/openapi/social.json

Repository: recoupable/docs

Length of output: 97


🏁 Script executed:

# Search for security declarations in the file
rg '"security"' api-reference/openapi/social.json

Repository: recoupable/docs

Length of output: 41


🏁 Script executed:

# Look at the global structure and components section
grep -n "components\|securitySchemes" api-reference/openapi/social.json | head -20

Repository: recoupable/docs

Length of output: 1547


🏁 Script executed:

# Check for the /api/connectors endpoint around lines 930-1099
sed -n '920,1110p' api-reference/openapi/social.json

Repository: recoupable/docs

Length of output: 5960


🏁 Script executed:

# Look for the components and securitySchemes section
sed -n '2600,$p' api-reference/openapi/social.json | head -150

Repository: recoupable/docs

Length of output: 3372


🏁 Script executed:

# Search for any global security at the root level
rg 'security|securitySchemes' -C 2 api-reference/openapi/social.json

Repository: recoupable/docs

Length of output: 152


🏁 Script executed:

# Check if there's a global security declaration at the root level of the document
sed -n '1,50p' api-reference/openapi/social.json | tail -30

Repository: recoupable/docs

Length of output: 1175


🏁 Script executed:

# Search more carefully for security at root level (between info and paths)
sed -n '1,20p' api-reference/openapi/social.json

Repository: recoupable/docs

Length of output: 470


🏁 Script executed:

# Check around the paths and components to see if there's a root-level security
python3 << 'EOF'
import json

with open('api-reference/openapi/social.json', 'r') as f:
    spec = json.load(f)

# Check if root has security
has_root_security = 'security' in spec
print(f"Root level 'security' field present: {has_root_security}")

# Check if /api/connectors operations have security
if '/api/connectors' in spec.get('paths', {}):
    connector_ops = spec['paths']['/api/connectors']
    for op in ['get', 'post', 'delete']:
        if op in connector_ops:
            has_op_security = 'security' in connector_ops[op]
            print(f"/api/connectors {op}: has 'security' = {has_op_security}")
            
# Verify security schemes exist
has_security_schemes = 'securitySchemes' in spec.get('components', {})
print(f"\nsecuritySchemes defined: {has_security_schemes}")
if has_security_schemes:
    schemes = list(spec['components']['securitySchemes'].keys())
    print(f"Available schemes: {schemes}")
EOF

Repository: recoupable/docs

Length of output: 316


Declare authentication on the connector endpoints.

GET/POST/DELETE /api/connectors document 401 and 403 responses indicating authentication is required, yet none of these operations declare security. Per OpenAPI 3.1 specification, endpoints without root-level or operation-level security declarations are treated as public. The spec defines bearerAuth and apiKeyAuth schemes but does not apply them to these endpoints.

🔐 Suggested fix pattern
       "get": {
+        "security": [
+          { "apiKeyAuth": [] },
+          { "bearerAuth": [] }
+        ],
         "description": "List available connectors and their connection status. Returns all supported third-party integrations (e.g., Google Sheets, TikTok) along with whether they are currently connected.",

Repeat for the post and delete operations on the same path.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"/api/connectors": {
"get": {
"description": "List available connectors and their connection status. Returns all supported third-party integrations (e.g., Google Sheets, TikTok) along with whether they are currently connected.",
"parameters": [
{
"name": "account_id",
"in": "query",
"description": "Optional account ID to get connectors for a different account (e.g., an artist, workspace, or organization). The authenticated account must have access to the specified account. Omit to get your own account's connectors.",
"required": false,
"schema": {
"type": "string",
"format": "uuid"
}
}
],
"responses": {
"200": {
"description": "Connectors retrieved successfully",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ConnectorsResponse"
}
}
}
},
"400": {
"description": "Bad request - invalid account_id format",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Unauthorized - invalid or missing API key",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Forbidden - no access to the specified account",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
},
"delete": {
"description": "Disconnect a connected account from a third-party service. This revokes the OAuth connection and removes stored credentials.",
"requestBody": {
"description": "Connection to disconnect",
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DisconnectConnectorRequest"
}
}
}
},
"responses": {
"200": {
"description": "Connector disconnected successfully",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DisconnectConnectorResponse"
}
}
}
},
"400": {
"description": "Bad request - missing or invalid parameters",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Unauthorized - invalid or missing API key",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Forbidden - no access to the specified account or connection",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
},
"post": {
"description": "Generate an OAuth authorization URL for connecting a third-party service. Redirect to the returned URL to complete the OAuth flow.",
"requestBody": {
"description": "Authorization request details",
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthorizeConnectorRequest"
}
}
}
},
"responses": {
"200": {
"description": "Authorization URL generated successfully",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthorizeConnectorResponse"
}
}
}
},
"400": {
"description": "Bad request - invalid connector or parameters",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Unauthorized - invalid or missing API key",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Forbidden - no access to the specified account",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
"/api/connectors": {
"get": {
"security": [
{ "apiKeyAuth": [] },
{ "bearerAuth": [] }
],
"description": "List available connectors and their connection status. Returns all supported third-party integrations (e.g., Google Sheets, TikTok) along with whether they are currently connected.",
"parameters": [
{
"name": "account_id",
"in": "query",
"description": "Optional account ID to get connectors for a different account (e.g., an artist, workspace, or organization). The authenticated account must have access to the specified account. Omit to get your own account's connectors.",
"required": false,
"schema": {
"type": "string",
"format": "uuid"
}
}
],
"responses": {
"200": {
"description": "Connectors retrieved successfully",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ConnectorsResponse"
}
}
}
},
"400": {
"description": "Bad request - invalid account_id format",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Unauthorized - invalid or missing API key",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Forbidden - no access to the specified account",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
},
"delete": {
"description": "Disconnect a connected account from a third-party service. This revokes the OAuth connection and removes stored credentials.",
"requestBody": {
"description": "Connection to disconnect",
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DisconnectConnectorRequest"
}
}
}
},
"responses": {
"200": {
"description": "Connector disconnected successfully",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DisconnectConnectorResponse"
}
}
}
},
"400": {
"description": "Bad request - missing or invalid parameters",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Unauthorized - invalid or missing API key",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Forbidden - no access to the specified account or connection",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
},
"post": {
"description": "Generate an OAuth authorization URL for connecting a third-party service. Redirect to the returned URL to complete the OAuth flow.",
"requestBody": {
"description": "Authorization request details",
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthorizeConnectorRequest"
}
}
}
},
"responses": {
"200": {
"description": "Authorization URL generated successfully",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthorizeConnectorResponse"
}
}
}
},
"400": {
"description": "Bad request - invalid connector or parameters",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Unauthorized - invalid or missing API key",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Forbidden - no access to the specified account",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api-reference/openapi/social.json` around lines 930 - 1099, The
GET/POST/DELETE operations under the "/api/connectors" path are missing
operation-level security declarations; add a security array to each operation
(get, post, delete) referencing the existing schemes (e.g., bearerAuth and/or
apiKeyAuth) so these endpoints are not treated as public—for each operation add
"security": [{"bearerAuth": []}, {"apiKeyAuth": []}] (or the appropriate scheme
combination) to enforce authentication.

Comment on lines +1127 to +1131
"error": {
"type": "string",
"nullable": true,
"description": "Error message if the run failed (null if successful)"
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, check if the file exists and read its OpenAPI version
head -20 api-reference/openapi/social.json

Repository: recoupable/docs

Length of output: 470


🏁 Script executed:

# Check the specific lines mentioned (1127-1131)
sed -n '1120,1135p' api-reference/openapi/social.json | cat -n

Repository: recoupable/docs

Length of output: 694


🏁 Script executed:

# Search for all instances of "nullable" in the file to see how many need fixing
rg -n 'nullable' api-reference/openapi/social.json | head -20

Repository: recoupable/docs

Length of output: 723


🌐 Web query:

OpenAPI 3.1 nullable removed JSON Schema union type null

💡 Result:

In OpenAPI 3.1, nullable was removed because OAS 3.1 aligns its Schema Object with JSON Schema (draft 2020-12), which already has a first-class null type—so you model “nullable” using a union that includes null. [1], [2]

Use a JSON Schema union with null

1) type as an array (most common)

schema:
  type: [string, "null"]

JSON Schema allows type to be an array of types (a union). [3]

2) oneOf / anyOf including { type: "null" }

schema:
  anyOf:
    - type: string
    - type: "null"

Reminder: “optional” vs “nullable”

  • Optional (may be omitted): control with required (object-level).
  • Nullable (may be present with value null): include "null" in the schema union.

Sources: OpenAPI Initiative notes on removing nullable [1]; OpenAPI 3.1 spec entry point/dialect [2]; JSON Schema reference on type as an array [3].

[1] https://www.openapis.org/2021/02
[2] https://spec.openapis.org/oas/v3.1.0
[3] https://json-schema.org/understanding-json-schema/reference/type


Replace all instances of nullable: true with OpenAPI 3.1-compliant union type syntax.

This file is declared as OpenAPI 3.1.0, but uses nullable: true, which was removed in favor of JSON Schema's first-class null type. The file currently has 20+ instances of nullable: true that need to be updated and will not validate cleanly against OpenAPI 3.1 schema.

Update properties using the union type pattern:

"type": ["string", "null"]

Instances to update are at lines: 1129, 1606, 1619, 1624, 1629, 1634, 1951, 1960, 1989, 1998, 2098, 2107, 2162, 2176, 2181, 2195, 2200, 2417, 2530, and others.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api-reference/openapi/social.json` around lines 1127 - 1131, The OpenAPI 3.1
spec in social.json still uses "nullable": true (e.g., the "error" property
shown) which is invalid; locate every property object containing "nullable":
true (including the listed instances) and remove "nullable": true, then replace
or update the property's "type" to the JSON-Schema union form by adding "null"
(for example change a string type to "type": ["string","null"] or an
object/array/number type to include null). Ensure you update each occurrence
consistently (search for "nullable": true), preserving existing type information
in the property's schema (for properties with no explicit "type", add the
appropriate union type including "null").

Comment on lines 1 to 4
---
title: 'Playlist'
openapi: 'GET /api/research/playlist'
openapi: "/api-reference/openapi/research.json GET /api/research/playlist"
---
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify that all referenced endpoints exist in their domain spec files

echo "Checking content.json for upscale and callback endpoints..."
jq -r '.paths | keys[]' api-reference/openapi/content.json | grep -E '(upscale|content-agent/callback)'

echo -e "\nChecking releases.json for artist-profile endpoint..."
jq -r '.paths | keys[]' api-reference/openapi/releases.json | grep 'artist-profile'

echo -e "\nChecking research.json for chats, curator, and playlist endpoints..."
jq -r '.paths | keys[]' api-reference/openapi/research.json | grep -E '(chats.*artist|curator|playlist)'

echo -e "\nChecking accounts.json for workspaces endpoint..."
jq -r '.paths | keys[]' api-reference/openapi/accounts.json | grep 'workspaces'

echo -e "\nChecking social.json for connectors endpoint..."
jq -r '.paths | keys[]' api-reference/openapi/social.json | grep 'connectors'

Repository: recoupable/docs

Length of output: 536


🏁 Script executed:

#!/bin/bash

# Find all api-reference MDX files to verify the "8 files" count and pattern
echo "=== All api-reference MDX files ==="
find api-reference -name "*.mdx" -type f | sort

echo -e "\n=== Content of mint.json (if exists) ==="
if [ -f "mint.json" ]; then
  head -50 mint.json
fi

echo -e "\n=== Checking for Mintlify config files ==="
ls -la | grep -E "mint|mintlify"

Repository: recoupable/docs

Length of output: 4606


🏁 Script executed:

#!/bin/bash

# Check the openapi frontmatter format in each api-reference MDX file
echo "=== Frontmatter format in api-reference MDX files ==="
find api-reference -name "*.mdx" -type f -exec sh -c '
  echo "File: $1"
  head -5 "$1"
  echo ""
' _ {} \;

Repository: recoupable/docs

Length of output: 18035


Address incomplete migration to new OpenAPI frontmatter format across the codebase.

Endpoint verification passed, but the codebase shows inconsistent OpenAPI frontmatter patterns. While playlist.mdx correctly uses the new format ("/api-reference/openapi/research.json GET /path"), many other api-reference files still use the old format (post /path). With 130+ api-reference MDX files total, this is not just a matter of "8 files" as mentioned.

Either migrate all api-reference MDX files to the new format or confirm the old format is still supported by Mintlify before merging. Inconsistent formats may cause rendering issues or "Try it" playground failures for files still using the legacy pattern.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api-reference/research/playlist.mdx` around lines 1 - 4, The repo has mixed
OpenAPI frontmatter formats (new style like openapi:
"/api-reference/openapi/research.json GET /api/research/playlist" in
playlist.mdx vs legacy "post /path" entries); scan all api-reference MDX files
for the old pattern (e.g., strings like "post /", "get /" used in frontmatter)
and either (A) convert them to the new frontmatter format matching playlist.mdx
(compose openapi value as "<openapi-json-path> <HTTP_METHOD> </path>") or (B)
confirm with Mintlify/maintainers that the legacy format is supported and
document that decision; update all affected files consistently and run the docs
build to verify the "Try it" playground and rendering work.

Comment on lines 1 to 4
---
title: 'Update Snapshot'
openapi: 'PATCH /api/sandboxes'
openapi: "/api-reference/openapi/content.json PATCH /api/sandboxes"
---
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify that endpoints referenced in MDX frontmatter exist in their target OpenAPI spec files

echo "Checking research.json for chat endpoints..."
if jq -e '.paths."/api/chats/{id}/messages/trailing".delete' api-reference/openapi/research.json > /dev/null 2>&1; then
  echo "✓ DELETE /api/chats/{id}/messages/trailing found in research.json"
else
  echo "✗ DELETE /api/chats/{id}/messages/trailing NOT found in research.json"
fi

echo -e "\nChecking social.json for social endpoints..."
for endpoint_path_method in \
  '"/api/social/scrape".post' \
  '"/api/posts".get' \
  '"/api/connectors".post' \
  '"/api/post/comments".get'; do
  
  path=$(echo "$endpoint_path_method" | cut -d. -f1)
  method=$(echo "$endpoint_path_method" | cut -d. -f2)
  
  if jq -e ".paths.$path.$method" api-reference/openapi/social.json > /dev/null 2>&1; then
    echo "$method $path found in social.json"
  else
    echo "$method $path NOT found in social.json"
  fi
done

echo -e "\nChecking accounts.json for account endpoints..."
if jq -e '.paths."/api/accounts/artists".post' api-reference/openapi/accounts.json > /dev/null 2>&1; then
  echo "✓ POST /api/accounts/artists found in accounts.json"
else
  echo "✗ POST /api/accounts/artists NOT found in accounts.json"
fi

echo -e "\nChecking content.json for sandbox endpoints..."
for endpoint_path_method in \
  '"/api/sandboxes/files".post' \
  '"/api/sandboxes".patch'; do
  
  path=$(echo "$endpoint_path_method" | cut -d. -f1)
  method=$(echo "$endpoint_path_method" | cut -d. -f2)
  
  if jq -e ".paths.$path.$method" api-reference/openapi/content.json > /dev/null 2>&1; then
    echo "$method $path found in content.json"
  else
    echo "$method $path NOT found in content.json"
  fi
done

Repository: recoupable/docs

Length of output: 646


Fix OpenAPI frontmatter format to exclude the spec file path.

The endpoint verification passed—all referenced endpoints exist in their target OpenAPI spec files. However, the frontmatter format is incorrect. According to the API reference guidelines, the openapi field should reference only the method and path, not the file path:

openapi: 'PATCH /api/sandboxes'

Remove the /api-reference/openapi/content.json prefix from the frontmatter.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api-reference/sandboxes/snapshot.mdx` around lines 1 - 4, Update the OpenAPI
frontmatter in snapshot.mdx by removing the spec file path prefix so the openapi
field contains only the method and path; change the existing openapi value that
currently reads "/api-reference/openapi/content.json PATCH /api/sandboxes" to
the short form "PATCH /api/sandboxes" in the frontmatter block so it conforms to
the API reference guidelines.

@sweetmantech
Copy link
Copy Markdown
Collaborator Author

Testing Results

Page Rendering — 127/127 pages pass

Tested every API reference page on localhost:3000 against prod (developers.recoupable.com):

  • 127/127 pages load with endpoint content (cURL examples, Try it buttons)
  • 127/127 match prod — no broken pages, no missing endpoints, no content differences
  • Visual spot-checks confirmed across all 5 domains: Accounts, Social Media, Research, Content, Releases

Raw HTML Size — 21% smaller pages

Page Local Prod Change
accounts/get 258KB 332KB -22%
content/generate-image 275KB 345KB -20%
research/search 269KB 343KB -22%
spotify/search 280KB 354KB -21%
tasks/get 311KB 384KB -19%
Average 279KB 352KB -21%

LLM Context Impact — 73-84% fewer tokens

The monolithic openapi.json consumed the entire GPT-4o 128K context window just for the API schema, leaving zero room for conversation.

Metric Before (monolith) After (split) Improvement
Tokens per query ~128K (always) 20K-34K (per domain) 73-84% fewer
GPT-4o 128K context used 100% 16-27% Leaves 73-84% for conversation
Files to parse 1 × 502KB 5 × 79-134KB Targeted loading

Per-domain breakdown:

File Size Paths Schemas Tokens
accounts.json 85KB 18 38 ~21,688
content.json 134KB 26 61 ~34,266
releases.json 97KB 14 64 ~24,783
research.json 110KB 39 87 ~28,252
social.json 79KB 16 52 ~20,308

Bottom line

A dev giving their LLM a link to a single domain spec now uses ~25K tokens instead of ~128K tokens, leaving room for actual code generation instead of filling the context window with unrelated endpoints.

🤖 Generated with Claude Code

@sweetmantech sweetmantech merged commit 0c38bd7 into main Apr 9, 2026
3 checks passed
sweetmantech added a commit that referenced this pull request Apr 9, 2026
Applied to the split content.json (after #121 merged):
1. Image: add num_images, aspect_ratio, resolution; fix model name; add images array
2. Video: make image_url required; document model limitation
3. Edit: remove image_url (not implemented)
4. Transcribe: rename songUrl → audioUrl
5. Upscale: add upscale_factor and target_resolution

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
sweetmantech added a commit that referenced this pull request Apr 9, 2026
* docs: align content OpenAPI spec with API implementation

Applied to the split content.json (after #121 merged):
1. Image: add num_images, aspect_ratio, resolution; fix model name; add images array
2. Video: make image_url required; document model limitation
3. Edit: remove image_url (not implemented)
4. Transcribe: rename songUrl → audioUrl
5. Upscale: add upscale_factor and target_resolution

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: align edit endpoint description with schema (remove image reference)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: add missing video mode response, transcribe params, fix caption examples

1. Video response: add mode field (prompt/animate/reference/extend/first-last/lipsync)
2. Transcribe request: add language, chunk_level, diarize params
3. Caption response: fix color examples to match API (white/black, maxFontSize 42)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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