Skip to content

fix: harden research API response schemas and add error responses#132

Merged
sweetmantech merged 1 commit intomainfrom
fix/research-response-schemas-v2
Apr 15, 2026
Merged

fix: harden research API response schemas and add error responses#132
sweetmantech merged 1 commit intomainfrom
fix/research-response-schemas-v2

Conversation

@sweetmantech
Copy link
Copy Markdown
Collaborator

@sweetmantech sweetmantech commented Apr 15, 2026

Summary

Ports the changes from closed PR #101 onto the split OpenAPI spec. The original PR modified api-reference/openapi.json (the old monolithic file), which has since been deleted on main and split into per-domain files under api-reference/openapi/. All research-related changes are re-applied here to api-reference/openapi/research.json.

This replaces closed PR #101.

  • Fix field name/type mismatches in research response schemas by cross-referencing actual API handler code
  • Add reusable ResearchErrorResponse component ({ status: "error", error: "message" })
  • Add 400 and 401 error responses to all 30 /api/research/* endpoints via $ref
  • Add example: "success" to all response schema status fields for consistency
  • Tighten /api/research/charts query parameter constraints (country ISO-2 pattern, interval/type enums, latest as boolean)
  • Strengthen /api/research/enrich request schema validation (must include type: "object" and properties)

Schema fixes (from #101)

Schema Change Reason
ResearchCareerResponse datacareer Handler returns { career: data }, not { data }
ResearchWebResponse items contentsnippet; added date, last_updated Perplexity returns snippet, not content
ResearchEnrichResponse Flattened research_basis.citations → top-level citations Handler returns { output, citations } flat
ResearchPeopleResult Added id, publishedDate, author Exa search returns these fields

Also restructures ResearchAudienceResponse, ResearchInstagramPostsResponse, and ResearchLookupResponse to match actual handler output (ported verbatim from #101).

Error responses added

All 30 /api/research/* endpoints now document:

  • 400 — Validation errors (missing params, invalid values)
  • 401 — Authentication failures (invalid/missing API key)

Both reference the shared ResearchErrorResponse schema.

Test plan

  • research.json parses as valid JSON
  • ResearchErrorResponse component present
  • 60/60 operation responses across 30 research paths have both 400 and 401 entries
  • All 20 status fields with enum: ["success","error"] have example: "success"
  • Verify Mintlify renders all 30 research endpoint docs correctly
  • Hit each endpoint with live requests and compare response shape to schema

Note: the original PR also edited cli.mdx; that change has already been handled on main and is intentionally not re-applied here.


Summary by cubic

Hardened the research API OpenAPI spec in api-reference/openapi/research.json by fixing response schemas and adding standardized error responses. This aligns docs with real handler output and improves validation.

  • New Features

    • Added shared ResearchErrorResponse and 400/401 responses to all /api/research/* endpoints.
    • Tightened /api/research/charts query params (ISO-2 country, interval/type enums with defaults, latest as boolean).
    • Required schema for /api/research/enrich to include type: "object" and properties; added example: "success" to all status fields.
  • Bug Fixes

    • Fixed schema mismatches to match real responses (e.g., career field in ResearchCareerResponse; snippet + date/last_updated in ResearchWebResponse; flattened citations in ResearchEnrichResponse; added id, publishedDate, author in ResearchPeopleResult).
    • Restructured ResearchAudienceResponse, ResearchInstagramPostsResponse, and ResearchLookupResponse to reflect actual handler output.

Written for commit 241fdea. Summary will update on new commits.

Summary by CodeRabbit

  • API Updates
    • Enhanced error responses with standardized 400 and 401 status codes across endpoints.
    • Improved query parameter validation and defaults for charts endpoint.
    • Restructured API response schemas with new fields, better data organization, and refined documentation for enriched results.

Supersedes closed PR #101, which modified the old monolithic
api-reference/openapi.json before the spec was split into per-domain
files. This ports the same changes onto api-reference/openapi/research.json.

- Add reusable ResearchErrorResponse component ({ status: "error", error })
- Add 400 and 401 error responses to all 30 /api/research/* endpoints
- Add example: "success" to every response schema status field with the
  success/error enum
- Tighten /api/research/charts query params (country ISO-2 pattern,
  interval/type enums with defaults, latest as boolean)
- Strengthen /api/research/enrich request schema (require type=object
  and properties)

Schema fixes (field name/type mismatches vs. actual handlers):

| Schema                          | Change                                              | Reason                                             |
|---------------------------------|-----------------------------------------------------|----------------------------------------------------|
| ResearchCareerResponse          | data -> career                                      | Handler returns { career: data }                   |
| ResearchWebResponse items       | content -> snippet; added date, last_updated        | Perplexity returns snippet                         |
| ResearchEnrichResponse          | Flattened research_basis.citations -> citations     | Handler returns { output, citations } flat         |
| ResearchPeopleResult            | Added id, publishedDate, author                     | Exa search returns these fields                    |

Also restructures ResearchAudienceResponse, ResearchInstagramPostsResponse,
and ResearchLookupResponse to match actual handler output (ported verbatim
from PR #101).
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 15, 2026

📝 Walkthrough

Walkthrough

The OpenAPI specification for the research API has been updated with new error response definitions (400/401 status codes), refined query parameter declarations with defaults and validation constraints, and restructured response/request schemas featuring field renames, new required properties, and redefined data shapes across multiple endpoints.

Changes

Cohort / File(s) Summary
Error Response Handling
api-reference/openapi/research.json
Added 400 and 401 response definitions with ResearchErrorResponse schema to multiple /api/research/* endpoints; introduced new ResearchErrorResponse component with required status and error fields.
Query Parameter Refinements
api-reference/openapi/research.json
Updated /api/research/charts parameters: country now requires ISO-2 format with pattern validation (^[A-Z]{2}$) and defaults to "US"; interval and type added enum constraints and defaults; latest changed from string to boolean type with default: true.
Response Schema Restructuring
api-reference/openapi/research.json
Renamed/replaced fields across multiple response schemas: ResearchAudienceResponse (replaced age/gender/countries with audience\_genders, top\_countries, etc.); ResearchCareerResponse (career\_stage → career); ResearchEnrichResponse (research\_basis → citations); ResearchInstagramPostsResponse (posts → top\_posts, added top\_reels); ResearchLookupResponse (moved IDs to nested data object); ResearchWebResponse (content → snippet, added date/last\_updated).
Request Schema Updates
api-reference/openapi/research.json
Strengthened ResearchEnrichRequest.schema to enforce JSON-Schema-like structure with required type: "object" and properties fields; updated endpoint description to require object-type schema.
Extract & People Result Refinements
api-reference/openapi/research.json
Added required: ["status","results"] to ResearchExtractResponse; added id, publishedDate, author fields to ResearchPeopleResult with nullable highlights; clarified error descriptions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 Our API hops with clearer form,
Error codes and schemas warm,
Defaults set, validations tight,
Responses renamed, fields alight—
A research garden, structured bright! 🌿

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: harden research API response schemas and add error responses' is directly related to the main change in the changeset, which focuses on strengthening API response schemas and adding error response documentation.
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 fix/research-response-schemas-v2

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

@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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
api-reference/openapi/research.json (2)

3903-3957: ⚠️ Potential issue | 🟡 Minor

Breaking change: posts renamed to top_posts, new top_reels added.

Field renamed from posts to top_posts and new top_reels array added to better reflect the Chartmetric DeepSocial data structure. Clients expecting the posts field will need to update.

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

In `@api-reference/openapi/research.json` around lines 3903 - 3957, Update the API
schema to reflect the breaking change: rename the old posts field to top_posts
and add the new top_reels array in the ResearchInstagramPostsResponse schema;
specifically, replace any references to "posts" with "top_posts" and ensure the
ResearchInstagramPostsResponse properties include both "top_posts" and
"top_reels" with the same item shape (url, likes, comments, timestamp) and
additionalProperties allowed, and update any docs/tests that reference
ResearchInstagramPostsResponse.posts to use
ResearchInstagramPostsResponse.top_posts (and use top_reels where applicable).

3444-3461: ⚠️ Potential issue | 🟡 Minor

Breaking change: career_stage renamed to career.

This renames the response field from career_stage to career based on the actual API handler output. Clients expecting the old field name will need to update their integrations.

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

In `@api-reference/openapi/research.json` around lines 3444 - 3461, The OpenAPI
schema defines ResearchCareerResponse with a property named "career" but the
change note says the field was renamed from "career_stage"; update any remaining
schema, examples, and references that still use "career_stage" to use "career"
consistently (or add a backward-compatible "career_stage" alias if you must
preserve compatibility); specifically search and update references to
ResearchCareerResponse and any examples or components that mention
"career_stage" so they match the actual API handler output "career".
🧹 Nitpick comments (1)
api-reference/openapi/research.json (1)

3397-3400: Status field missing enum constraint.

Unlike other response schemas (e.g., ResearchAlbumsResponse), ResearchAudienceResponse.status lacks the enum: ["success", "error"] constraint. This inconsistency could affect client-side validation.

♻️ Suggested fix
           "status": {
             "type": "string",
+            "enum": ["success", "error"],
             "example": "success"
           },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api-reference/openapi/research.json` around lines 3397 - 3400, The status
field in ResearchAudienceResponse (the property named status) is missing the
enum constraint; update the schema for ResearchAudienceResponse.status to
include enum: ["success", "error"] so it matches other response schemas and
enables consistent client-side validation.
🤖 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/openapi/research.json`:
- Around line 3958-3987: The OpenAPI schema for ResearchLookupResponse was
changed so cross-platform IDs are nested under the "data" object
(ResearchLookupResponse -> properties -> data) instead of being top-level
properties; update any server/client code or docs that read top-level fields to
instead read ResearchLookupResponse.data.id,
ResearchLookupResponse.data.spotify_id,
ResearchLookupResponse.data.apple_music_id, and
ResearchLookupResponse.data.deezer_id, and ensure JSON serializers/deserializers
and type definitions (models/DTOs) reflect the nested "data" object with
additionalProperties allowed.
- Around line 4586-4599: The OpenAPI schema was changed: the response field
previously named "content" has been renamed to "snippet" and two new nullable
fields "date" and "last_updated" were added; update all usages and examples to
reference "snippet" (not "content"), add the new "date" and "last_updated"
properties to any model definitions and response examples, and update any
serialization/deserialization logic or client mappings that expect "content"
(search result models, e.g., the search result type) so they read/write
"snippet" and handle nullable "date" and "last_updated" values appropriately.
- Around line 3654-3673: The OpenAPI change made ResearchEnrichRequest.schema
require explicit "type" and "properties", which breaks existing clients; revert
this breaking change by making the schema permissive again: update
ResearchEnrichRequest.schema to accept either the new strict form or the
previous unconstrained object (e.g., replace the strict
required=["type","properties"] model with a oneOf that includes both the strict
object (with "type":"object" + "properties") and a generic object schema
allowing additionalProperties), and add/update the endpoint description to note
the preferred new strict schema and a deprecation/compatibility note for the
older form.

---

Outside diff comments:
In `@api-reference/openapi/research.json`:
- Around line 3903-3957: Update the API schema to reflect the breaking change:
rename the old posts field to top_posts and add the new top_reels array in the
ResearchInstagramPostsResponse schema; specifically, replace any references to
"posts" with "top_posts" and ensure the ResearchInstagramPostsResponse
properties include both "top_posts" and "top_reels" with the same item shape
(url, likes, comments, timestamp) and additionalProperties allowed, and update
any docs/tests that reference ResearchInstagramPostsResponse.posts to use
ResearchInstagramPostsResponse.top_posts (and use top_reels where applicable).
- Around line 3444-3461: The OpenAPI schema defines ResearchCareerResponse with
a property named "career" but the change note says the field was renamed from
"career_stage"; update any remaining schema, examples, and references that still
use "career_stage" to use "career" consistently (or add a backward-compatible
"career_stage" alias if you must preserve compatibility); specifically search
and update references to ResearchCareerResponse and any examples or components
that mention "career_stage" so they match the actual API handler output
"career".

---

Nitpick comments:
In `@api-reference/openapi/research.json`:
- Around line 3397-3400: The status field in ResearchAudienceResponse (the
property named status) is missing the enum constraint; update the schema for
ResearchAudienceResponse.status to include enum: ["success", "error"] so it
matches other response schemas and enables consistent client-side validation.
🪄 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: be144923-67e2-4d6f-8b2e-7c41f8ca78ea

📥 Commits

Reviewing files that changed from the base of the PR and between e6c9752 and 241fdea.

📒 Files selected for processing (1)
  • api-reference/openapi/research.json

Comment on lines +3654 to +3673
"description": "JSON schema defining the fields to extract. Must include `\"type\": \"object\"` at the top level.",
"additionalProperties": true,
"properties": {
"type": {
"type": "string",
"enum": [
"object"
],
"description": "Must be \"object\""
},
"properties": {
"type": "object",
"description": "Field definitions to extract",
"additionalProperties": true
}
},
"required": [
"type",
"properties"
]
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

Breaking change: schema now requires explicit type and properties fields.

The ResearchEnrichRequest.schema now enforces that requests must include "type": "object" and "properties" at the top level. While the endpoint description at line 1391 documents this requirement, existing clients that relied on the previously unconstrained schema object will receive 400 errors.

Consider whether this warrants a deprecation period or if the prior behavior was already rejecting such requests server-side.

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

In `@api-reference/openapi/research.json` around lines 3654 - 3673, The OpenAPI
change made ResearchEnrichRequest.schema require explicit "type" and
"properties", which breaks existing clients; revert this breaking change by
making the schema permissive again: update ResearchEnrichRequest.schema to
accept either the new strict form or the previous unconstrained object (e.g.,
replace the strict required=["type","properties"] model with a oneOf that
includes both the strict object (with "type":"object" + "properties") and a
generic object schema allowing additionalProperties), and add/update the
endpoint description to note the preferred new strict schema and a
deprecation/compatibility note for the older form.

Comment on lines 3958 to 3987
"ResearchLookupResponse": {
"type": "object",
"description": "Artist profile resolved from a platform URL or ID.",
"description": "Artist profile resolved from a platform URL or ID. Cross-platform IDs are nested inside a `data` object.",
"properties": {
"status": {
"type": "string"
},
"id": {
"type": "integer",
"description": "Chartmetric artist ID"
},
"spotify_id": {
"type": "string"
},
"apple_music_id": {
"type": "string"
"type": "string",
"example": "success"
},
"deezer_id": {
"type": "string"
"data": {
"type": "object",
"description": "Cross-platform artist identifiers returned by Chartmetric.",
"properties": {
"id": {
"type": "integer",
"description": "Chartmetric artist ID"
},
"spotify_id": {
"type": "string"
},
"apple_music_id": {
"type": "string"
},
"deezer_id": {
"type": "string"
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
},
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

Breaking change: Cross-platform IDs moved into nested data object.

The response structure changed from top-level ID fields to a nested data object containing id, spotify_id, apple_music_id, and deezer_id. Clients directly accessing these fields at the response root will need updates.

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

In `@api-reference/openapi/research.json` around lines 3958 - 3987, The OpenAPI
schema for ResearchLookupResponse was changed so cross-platform IDs are nested
under the "data" object (ResearchLookupResponse -> properties -> data) instead
of being top-level properties; update any server/client code or docs that read
top-level fields to instead read ResearchLookupResponse.data.id,
ResearchLookupResponse.data.spotify_id,
ResearchLookupResponse.data.apple_music_id, and
ResearchLookupResponse.data.deezer_id, and ensure JSON serializers/deserializers
and type definitions (models/DTOs) reflect the nested "data" object with
additionalProperties allowed.

Comment on lines +4586 to 4599
"snippet": {
"type": "string",
"description": "Content snippet from the search result."
},
"date": {
"type": "string",
"nullable": true,
"description": "Publication date if available."
},
"last_updated": {
"type": "string",
"nullable": true,
"description": "Last updated date if available."
}
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

Breaking change: content renamed to snippet, new date fields added.

The content field is renamed to snippet for clarity. The new date and last_updated nullable fields are useful additions for temporal context in search results.

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

In `@api-reference/openapi/research.json` around lines 4586 - 4599, The OpenAPI
schema was changed: the response field previously named "content" has been
renamed to "snippet" and two new nullable fields "date" and "last_updated" were
added; update all usages and examples to reference "snippet" (not "content"),
add the new "date" and "last_updated" properties to any model definitions and
response examples, and update any serialization/deserialization logic or client
mappings that expect "content" (search result models, e.g., the search result
type) so they read/write "snippet" and handle nullable "date" and "last_updated"
values appropriately.

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.

1 issue found across 1 file

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="api-reference/openapi/research.json">

<violation number="1" location="api-reference/openapi/research.json:2953">
P1: Custom agent: **Flag AI Slop and Fabricated Changes**

The `enum: ["success", "error"]` constraint is silently removed from `ResearchEnrichResponse.status` (and identically from `ResearchWebResponse.status`), replaced with only `example: "success"`. The PR description and test plan explicitly claim all 20 enum-bearing status fields retain their enum — that claim is false for these two schemas. This weakens schema validation: clients and code generators will no longer constrain the status field to known values. Restore the enum alongside the example to match every other research response schema in this file.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

],
"description": "Status of the request"
"description": "Status of the request",
"example": "success"
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Apr 15, 2026

Choose a reason for hiding this comment

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

P1: Custom agent: Flag AI Slop and Fabricated Changes

The enum: ["success", "error"] constraint is silently removed from ResearchEnrichResponse.status (and identically from ResearchWebResponse.status), replaced with only example: "success". The PR description and test plan explicitly claim all 20 enum-bearing status fields retain their enum — that claim is false for these two schemas. This weakens schema validation: clients and code generators will no longer constrain the status field to known values. Restore the enum alongside the example to match every other research response schema in this file.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At api-reference/openapi/research.json, line 2953:

<comment>The `enum: ["success", "error"]` constraint is silently removed from `ResearchEnrichResponse.status` (and identically from `ResearchWebResponse.status`), replaced with only `example: "success"`. The PR description and test plan explicitly claim all 20 enum-bearing status fields retain their enum — that claim is false for these two schemas. This weakens schema validation: clients and code generators will no longer constrain the status field to known values. Restore the enum alongside the example to match every other research response schema in this file.</comment>

<file context>
@@ -2335,7 +2949,8 @@
             ],
-            "description": "Status of the request"
+            "description": "Status of the request",
+            "example": "success"
           },
           "source_chat_id": {
</file context>
Fix with Cubic

@sweetmantech sweetmantech merged commit e652ae7 into main Apr 15, 2026
3 checks passed
recoupableorg pushed a commit that referenced this pull request Apr 20, 2026
Combine the design/narrative overhaul (new 8-tab IA, deprecation notices,
rebuilt Agent Onboarding, achromatic design system) with all API doc updates
shipped to main since the branch diverged:

- 8 research PRs (#132-#140): schema hardening, /research/track id-proxy,
  /research/curator Chartmetric contract, /research/track/playlists, error
  responses aligned with handler enforcement
- Artist surface rename: /api/artist/socials -> /api/artists/{id}/socials
- New endpoints: artists/pin, artists/unpin, admins/agent-signups
- Removed dead surfaces: artist/segments, chat/segment, segment/fans
- Caption length default -> none

Conflict resolutions:
- docs.json: kept design IA (Overview/Chat/Research/Artists/Catalog/Content/
  Automation/Accounts), spliced in all new endpoints from main, removed
  stale nav refs to deleted surfaces
- index.mdx, quickstart.mdx: kept design copy (richer, superseded main's
  verbose endpoint listing with card-based IA)
- openapi/content.json: auto-merge preserved design's deprecation of
  /api/content/create alongside main's untouched body

research.json, accounts.json, releases.json are byte-identical to main.
131 API mdx files / 131 nav entries / 0 orphans / 0 broken intra-doc links.

Made-with: Cursor
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