From 5c11c653780c0f8cfc94aed1f014bbdf8189f90e Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Sun, 13 Sep 2026 15:44:32 -0500 Subject: [PATCH 01/25] docs(api): document keyless feedback in the v2 reference --- api-reference/endpoint/feedback.mdx | 69 +- api-reference/endpoint/parse.mdx | 4 + api-reference/endpoint/scrape.mdx | 4 + api-reference/endpoint/search.mdx | 4 + api-reference/v2-openapi.json | 1349 ++++++++++++++++++++++++++- 5 files changed, 1421 insertions(+), 9 deletions(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index 478bc699a..9900ee73a 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -1,14 +1,75 @@ --- title: 'Endpoint Feedback' -description: 'Submit feedback for a completed v2 endpoint job.' +description: 'Submit feedback for a v2 endpoint job.' openapi: '/api-reference/v2-openapi.json POST /feedback' --- -Use endpoint feedback to tell Firecrawl whether a completed job result was useful, partial, or bad. This is for endpoint-level output quality on jobs such as `scrape`, `parse`, `map`, and `search`. +Use endpoint feedback to tell Firecrawl whether a job result met your task's needs. -The generic feedback schema can carry search-style fields too, but [Search Feedback](/api-reference/endpoint/search-feedback) is the preferred search-specific entry point because it is scoped to a search job ID and highlights valuable sources, missing content, query suggestions, and refund behavior. +## Keyless feedback -### Example Request +Eligible keyless callers submit optional evidence through `POST /v2/feedback`. Search, Scrape, and Parse use the same identity and submission limits across API, MCP, and CLI. An API key is not required. The authenticated feedback routes keep their existing request contracts. + +A submission requires `endpoint`, `jobId`, `rating` (`good`, `partial`, or `bad`), `task`, `assessment`, and 1-20 `observations`. Task, assessment, and observation detail must each contain 10-2000 characters after trimming. These bounds reject empty or very short answers; they cannot guarantee factual accuracy. + +Each observation requires `kind`, `detail`, and `basis`. Use `output` for observations about returned content, `source_comparison` for comparisons already made, and `expectation` for unmet expectations that have not been verified against a source. A source comparison requires `comparison: {reference, detail}`. Do not guess missing content, diagnose root causes, or investigate solely to submit feedback. Unmentioned results are unassessed. + +Search: useful and irrelevant require a one-based position within the delivered group. source names the response group the position refers to: web, images, or news. It is required only when the job requested multiple sources; otherwise it defaults to web. The position must exist in that requested group. irrelevant requires reason: aggregator_over_official, off_topic, stale, wrong_content_type, snippet_misleading, or blocked_or_paywalled. vertical is required on missing and optional on useful/irrelevant: web_general, social, business, research, developer, news, government, finance, or other. missing may include topic (up to 200 characters) and knownSources (up to 20 HTTP(S) URLs). Do not submit engine attribution; it comes from the stored category tag at that position. + +Scrape: kind correct, wrong_success, incomplete, or incorrect. wrong_success requires reason: blocked_shell, login_required, paywall, empty, wrong_page, stale, or wrong_locale. incomplete requires reason: partial_content, dynamic_content, pagination, main_content_stripped, or format_lost. incorrect requires reason: wrong, hallucinated, or missing_fields. correct has no reason. Optional location is up to 200 characters. No retryOutcome. Hard-failed Scrape jobs receive no feedback invitation. + +Parse: docClass is required once per submission: born_digital, scanned, mixed, or unknown. Observation kind: correct, text_ocr, table, formula, chart_figure, reading_order, headers_footers, headings_formatting, completeness, images_dropped, or incorrect. text_ocr requires reason: misread_chars, garbled, or missing_text. table requires reason: structure, cells_glued, or digits. completeness requires reason: pages_missing, truncated_at_max_pages, or sections_dropped. incorrect requires reason: wrong, hallucinated, or missing_fields. Other kinds have no reason subtype. Optional page is a one-based positive integer. + +Scrape and Parse: format must be a format type the job requested. It is required for output and source_comparison observations when multiple formats were requested; optional for expectation observations and single-format jobs. All observations retain detail and basis; source_comparison requires `comparison: {reference, detail}`. + +```json +{ + "endpoint": "search", + "jobId": "00000000-0000-4000-8000-000000000001", + "rating": "partial", + "task": "Find the documented retry behavior", + "assessment": "The API reference answered the retry question, but the news result did not.", + "observations": [ + { + "kind": "useful", + "source": "web", + "position": 1, + "basis": "output", + "detail": "The reference specifies the retry intervals." + }, + { + "kind": "irrelevant", + "reason": "off_topic", + "source": "news", + "position": 1, + "basis": "output", + "detail": "The announcement does not discuss retry behavior." + } + ] +} +``` + +## Discovery and clients + +Search returns its `id` and optional top-level `metadata`. Scrape and Parse include `jobId` and optional `feedback` in `data.metadata`. Execution failures can include top-level `metadata`. Submit feedback using the job reference returned for the same caller and endpoint. + +MCP exposes `firecrawl_feedback`. CLI exposes `firecrawl feedback --rating --task --assessment --observations-file `. Parse submissions also require `docClass`, passed as `--doc-class` in CLI. CLI invitations use stderr, preserving ordinary stdout; JSON results retain metadata. + +Eligible responses may include an optional invitation to submit feedback. Submissions remain optional and are never required for continued keyless access. + +## Submission behavior + +One new submission is accepted per keyless identity per UTC day, shared across Search, Scrape, Parse, and all clients. A retry for the same eligible job returns the original feedback ID with `alreadySubmitted: true`. Feedback does not consume or restore operation allowance. + +A job may no longer be eligible when feedback is submitted. + +Accepted feedback is stored with the originating request options and available result context. Jobs that disallow data retention are excluded. + +## Authenticated feedback + +When using an API key, keep using the existing endpoint feedback fields for `scrape`, `parse`, `map`, and `search`. For authenticated Search jobs, [Search Feedback](/api-reference/endpoint/search-feedback) remains the search-specific entry point. Its request format and refund behavior are unchanged. + +### Example request with an API key ```bash curl -X POST "https://api.firecrawl.dev/v2/feedback" \ diff --git a/api-reference/endpoint/parse.mdx b/api-reference/endpoint/parse.mdx index 418cecc2a..286d6187d 100644 --- a/api-reference/endpoint/parse.mdx +++ b/api-reference/endpoint/parse.mdx @@ -22,3 +22,7 @@ Use `/parse` when the source document is **a local file** or **not publicly acce **Using Firecrawl through MCP?** Use `firecrawl_parse` for local files. Local MCP can read the file directly when configured with `FIRECRAWL_API_URL`. Remote hosted MCP returns a short-lived upload command first, then parses the returned `uploadRef`. Public document URLs should still use `/scrape`. + +## Optional keyless feedback + +Eligible keyless responses may include an invitation to submit [endpoint feedback](/api-reference/endpoint/feedback). Use the returned `jobId` and observations already available from your task. Submitting feedback is optional. diff --git a/api-reference/endpoint/scrape.mdx b/api-reference/endpoint/scrape.mdx index 8c99698ca..e7ee84814 100644 --- a/api-reference/endpoint/scrape.mdx +++ b/api-reference/endpoint/scrape.mdx @@ -16,3 +16,7 @@ See the [Interact documentation](/features/interact) for full details and exampl Optionally you can also use the `actions` parameter, although it's not recommended to use it for complex interactions. > Are you an AI agent that needs a Firecrawl API key? See [firecrawl.dev/agent-onboarding/SKILL.md](https://www.firecrawl.dev/agent-onboarding/SKILL.md) for automated onboarding instructions. + +## Optional keyless feedback + +Eligible keyless responses may include an invitation to submit [endpoint feedback](/api-reference/endpoint/feedback). Use the returned `jobId` and observations already available from your task. Submitting feedback is optional. diff --git a/api-reference/endpoint/search.mdx b/api-reference/endpoint/search.mdx index 7b2334538..785ffa749 100644 --- a/api-reference/endpoint/search.mdx +++ b/api-reference/endpoint/search.mdx @@ -124,3 +124,7 @@ Each result includes a `category` field indicating its source: Use the `tbs` parameter to filter results by time periods, including custom date ranges. See the [Search Feature documentation](https://docs.firecrawl.dev/features/search#time-based-search) for detailed examples and supported formats. > Are you an AI agent that needs a Firecrawl API key? See [firecrawl.dev/agent-onboarding/SKILL.md](https://www.firecrawl.dev/agent-onboarding/SKILL.md) for automated onboarding instructions. + +## Optional keyless feedback + +Eligible keyless responses may include an invitation to submit [endpoint feedback](/api-reference/endpoint/feedback). Use the returned `id` and observations already available from your task. Submitting feedback is optional. diff --git a/api-reference/v2-openapi.json b/api-reference/v2-openapi.json index 84f20d67c..5e6b0452a 100644 --- a/api-reference/v2-openapi.json +++ b/api-reference/v2-openapi.json @@ -566,7 +566,8 @@ } } } - } + }, + "description": "Eligible keyless responses may include an optional feedback invitation in data.metadata. Submit feedback for this job through POST /v2/feedback using the returned jobId." } }, "/scrape/{jobId}/interact": { @@ -1075,7 +1076,8 @@ } } } - } + }, + "description": "Eligible keyless responses may include an optional feedback invitation in data.metadata. Submit feedback for this job through POST /v2/feedback using the returned jobId." } }, "/batch/scrape": { @@ -4508,7 +4510,8 @@ } } } - } + }, + "description": "Eligible keyless responses may include an optional feedback invitation in top-level metadata. Submit feedback for this job through POST /v2/feedback using the returned id." } }, "/interact": { @@ -6006,6 +6009,7 @@ "Feedback" ], "security": [ + {}, { "bearerAuth": [] } @@ -6015,7 +6019,19 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EndpointFeedbackRequest" + "anyOf": [ + { + "$ref": "#/components/schemas/KeylessFeedbackRequest" + }, + { + "title": "Authenticated feedback", + "allOf": [ + { + "$ref": "#/components/schemas/EndpointFeedbackRequest" + } + ] + } + ] } } } @@ -6080,8 +6096,29 @@ } } } + }, + "429": { + "description": "Too many feedback requests", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeedbackErrorResponse" + } + } + } + }, + "503": { + "description": "Feedback is temporarily unavailable", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeedbackErrorResponse" + } + } + } } - } + }, + "description": "Submit optional feedback for a Search, Scrape, or Parse job. Keyless callers use KeylessFeedbackRequest and may submit once per identity per UTC day, shared across all three categories and clients. Authenticated callers continue to use EndpointFeedbackRequest." } }, "/team/threat-protection": { @@ -11768,6 +11805,1308 @@ "description": "What to do when the classifier can't be reached: `closed` blocks the request, `open` allows it." } } + }, + "KeylessFeedbackRequest": { + "anyOf": [ + { + "type": "object", + "properties": { + "jobId": { + "type": "string", + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", + "description": "Job reference returned for the same caller and endpoint." + }, + "rating": { + "type": "string", + "enum": [ + "good", + "partial", + "bad" + ] + }, + "task": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + }, + "assessment": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + }, + "origin": { + "default": "api", + "type": "string", + "maxLength": 100 + }, + "integration": { + "nullable": true, + "type": "string", + "maxLength": 100 + }, + "endpoint": { + "type": "string", + "enum": [ + "search" + ] + }, + "observations": { + "minItems": 1, + "maxItems": 20, + "type": "array", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + }, + "basis": { + "type": "string", + "enum": [ + "output", + "source_comparison", + "expectation" + ], + "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + }, + "comparison": { + "type": "object", + "properties": { + "reference": { + "type": "string", + "minLength": 1, + "maxLength": 2048 + }, + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + } + }, + "required": [ + "reference", + "detail" + ], + "additionalProperties": false + }, + "source": { + "type": "string", + "enum": [ + "web", + "images", + "news" + ], + "description": "Response group the position refers to. Required when the job requested multiple sources; otherwise defaults to web. The source and position must exist in the requested, delivered results." + }, + "position": { + "type": "integer", + "maximum": 9007199254740991, + "description": "One-based position within the delivered response group. Engine attribution comes from the stored category tag at that position.", + "minimum": 1 + }, + "vertical": { + "type": "string", + "enum": [ + "web_general", + "social", + "business", + "research", + "developer", + "news", + "government", + "finance", + "other" + ] + }, + "kind": { + "type": "string", + "enum": [ + "useful" + ] + } + }, + "required": [ + "detail", + "basis", + "position", + "kind" + ], + "additionalProperties": false, + "title": "useful", + "anyOf": [ + { + "properties": { + "basis": { + "enum": [ + "output", + "expectation" + ] + } + } + }, + { + "required": [ + "comparison" + ] + } + ] + }, + { + "type": "object", + "properties": { + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + }, + "basis": { + "type": "string", + "enum": [ + "output", + "source_comparison", + "expectation" + ], + "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + }, + "comparison": { + "type": "object", + "properties": { + "reference": { + "type": "string", + "minLength": 1, + "maxLength": 2048 + }, + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + } + }, + "required": [ + "reference", + "detail" + ], + "additionalProperties": false + }, + "source": { + "type": "string", + "enum": [ + "web", + "images", + "news" + ], + "description": "Response group the position refers to. Required when the job requested multiple sources; otherwise defaults to web. The source and position must exist in the requested, delivered results." + }, + "position": { + "type": "integer", + "maximum": 9007199254740991, + "description": "One-based position within the delivered response group. Engine attribution comes from the stored category tag at that position.", + "minimum": 1 + }, + "vertical": { + "type": "string", + "enum": [ + "web_general", + "social", + "business", + "research", + "developer", + "news", + "government", + "finance", + "other" + ] + }, + "kind": { + "type": "string", + "enum": [ + "irrelevant" + ] + }, + "reason": { + "type": "string", + "enum": [ + "aggregator_over_official", + "off_topic", + "stale", + "wrong_content_type", + "snippet_misleading", + "blocked_or_paywalled" + ] + } + }, + "required": [ + "detail", + "basis", + "position", + "kind", + "reason" + ], + "additionalProperties": false, + "title": "irrelevant", + "anyOf": [ + { + "properties": { + "basis": { + "enum": [ + "output", + "expectation" + ] + } + } + }, + { + "required": [ + "comparison" + ] + } + ] + }, + { + "type": "object", + "properties": { + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + }, + "basis": { + "type": "string", + "enum": [ + "output", + "source_comparison", + "expectation" + ], + "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + }, + "comparison": { + "type": "object", + "properties": { + "reference": { + "type": "string", + "minLength": 1, + "maxLength": 2048 + }, + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + } + }, + "required": [ + "reference", + "detail" + ], + "additionalProperties": false + }, + "kind": { + "type": "string", + "enum": [ + "missing" + ] + }, + "vertical": { + "type": "string", + "enum": [ + "web_general", + "social", + "business", + "research", + "developer", + "news", + "government", + "finance", + "other" + ] + }, + "topic": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "knownSources": { + "maxItems": 20, + "type": "array", + "items": { + "type": "string", + "format": "uri", + "pattern": "^https?://" + } + } + }, + "required": [ + "detail", + "basis", + "kind", + "vertical" + ], + "additionalProperties": false, + "title": "missing", + "anyOf": [ + { + "properties": { + "basis": { + "enum": [ + "output", + "expectation" + ] + } + } + }, + { + "required": [ + "comparison" + ] + } + ] + } + ] + } + } + }, + "required": [ + "jobId", + "rating", + "task", + "assessment", + "endpoint", + "observations" + ], + "additionalProperties": false, + "title": "Keyless Search" + }, + { + "type": "object", + "properties": { + "jobId": { + "type": "string", + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", + "description": "Job reference returned for the same caller and endpoint." + }, + "rating": { + "type": "string", + "enum": [ + "good", + "partial", + "bad" + ] + }, + "task": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + }, + "assessment": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + }, + "origin": { + "default": "api", + "type": "string", + "maxLength": 100 + }, + "integration": { + "nullable": true, + "type": "string", + "maxLength": 100 + }, + "endpoint": { + "type": "string", + "enum": [ + "scrape" + ] + }, + "observations": { + "minItems": 1, + "maxItems": 20, + "type": "array", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + }, + "basis": { + "type": "string", + "enum": [ + "output", + "source_comparison", + "expectation" + ], + "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + }, + "comparison": { + "type": "object", + "properties": { + "reference": { + "type": "string", + "minLength": 1, + "maxLength": 2048 + }, + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + } + }, + "required": [ + "reference", + "detail" + ], + "additionalProperties": false + }, + "format": { + "type": "string", + "minLength": 1, + "description": "A format type requested by the job. Required for output and source_comparison observations when multiple formats were requested; optional otherwise." + }, + "location": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "kind": { + "type": "string", + "enum": [ + "correct" + ] + } + }, + "required": [ + "detail", + "basis", + "kind" + ], + "additionalProperties": false, + "title": "correct", + "anyOf": [ + { + "properties": { + "basis": { + "enum": [ + "output", + "expectation" + ] + } + } + }, + { + "required": [ + "comparison" + ] + } + ] + }, + { + "type": "object", + "properties": { + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + }, + "basis": { + "type": "string", + "enum": [ + "output", + "source_comparison", + "expectation" + ], + "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + }, + "comparison": { + "type": "object", + "properties": { + "reference": { + "type": "string", + "minLength": 1, + "maxLength": 2048 + }, + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + } + }, + "required": [ + "reference", + "detail" + ], + "additionalProperties": false + }, + "format": { + "type": "string", + "minLength": 1, + "description": "A format type requested by the job. Required for output and source_comparison observations when multiple formats were requested; optional otherwise." + }, + "location": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "kind": { + "type": "string", + "enum": [ + "wrong_success" + ] + }, + "reason": { + "type": "string", + "enum": [ + "blocked_shell", + "login_required", + "paywall", + "empty", + "wrong_page", + "stale", + "wrong_locale" + ] + } + }, + "required": [ + "detail", + "basis", + "kind", + "reason" + ], + "additionalProperties": false, + "title": "wrong_success", + "anyOf": [ + { + "properties": { + "basis": { + "enum": [ + "output", + "expectation" + ] + } + } + }, + { + "required": [ + "comparison" + ] + } + ] + }, + { + "type": "object", + "properties": { + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + }, + "basis": { + "type": "string", + "enum": [ + "output", + "source_comparison", + "expectation" + ], + "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + }, + "comparison": { + "type": "object", + "properties": { + "reference": { + "type": "string", + "minLength": 1, + "maxLength": 2048 + }, + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + } + }, + "required": [ + "reference", + "detail" + ], + "additionalProperties": false + }, + "format": { + "type": "string", + "minLength": 1, + "description": "A format type requested by the job. Required for output and source_comparison observations when multiple formats were requested; optional otherwise." + }, + "location": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "kind": { + "type": "string", + "enum": [ + "incomplete" + ] + }, + "reason": { + "type": "string", + "enum": [ + "partial_content", + "dynamic_content", + "pagination", + "main_content_stripped", + "format_lost" + ] + } + }, + "required": [ + "detail", + "basis", + "kind", + "reason" + ], + "additionalProperties": false, + "title": "incomplete", + "anyOf": [ + { + "properties": { + "basis": { + "enum": [ + "output", + "expectation" + ] + } + } + }, + { + "required": [ + "comparison" + ] + } + ] + }, + { + "type": "object", + "properties": { + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + }, + "basis": { + "type": "string", + "enum": [ + "output", + "source_comparison", + "expectation" + ], + "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + }, + "comparison": { + "type": "object", + "properties": { + "reference": { + "type": "string", + "minLength": 1, + "maxLength": 2048 + }, + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + } + }, + "required": [ + "reference", + "detail" + ], + "additionalProperties": false + }, + "format": { + "type": "string", + "minLength": 1, + "description": "A format type requested by the job. Required for output and source_comparison observations when multiple formats were requested; optional otherwise." + }, + "location": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "kind": { + "type": "string", + "enum": [ + "incorrect" + ] + }, + "reason": { + "type": "string", + "enum": [ + "wrong", + "hallucinated", + "missing_fields" + ] + } + }, + "required": [ + "detail", + "basis", + "kind", + "reason" + ], + "additionalProperties": false, + "title": "incorrect", + "anyOf": [ + { + "properties": { + "basis": { + "enum": [ + "output", + "expectation" + ] + } + } + }, + { + "required": [ + "comparison" + ] + } + ] + } + ] + } + } + }, + "required": [ + "jobId", + "rating", + "task", + "assessment", + "endpoint", + "observations" + ], + "additionalProperties": false, + "title": "Keyless Scrape" + }, + { + "type": "object", + "properties": { + "jobId": { + "type": "string", + "format": "uuid", + "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", + "description": "Job reference returned for the same caller and endpoint." + }, + "rating": { + "type": "string", + "enum": [ + "good", + "partial", + "bad" + ] + }, + "task": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + }, + "assessment": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + }, + "origin": { + "default": "api", + "type": "string", + "maxLength": 100 + }, + "integration": { + "nullable": true, + "type": "string", + "maxLength": 100 + }, + "endpoint": { + "type": "string", + "enum": [ + "parse" + ] + }, + "docClass": { + "type": "string", + "enum": [ + "born_digital", + "scanned", + "mixed", + "unknown" + ], + "description": "Document class, provided once for the submission. Use unknown when the class is not already known." + }, + "observations": { + "minItems": 1, + "maxItems": 20, + "type": "array", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + }, + "basis": { + "type": "string", + "enum": [ + "output", + "source_comparison", + "expectation" + ], + "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + }, + "comparison": { + "type": "object", + "properties": { + "reference": { + "type": "string", + "minLength": 1, + "maxLength": 2048 + }, + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + } + }, + "required": [ + "reference", + "detail" + ], + "additionalProperties": false + }, + "format": { + "type": "string", + "minLength": 1, + "description": "A format type requested by the job. Required for output and source_comparison observations when multiple formats were requested; optional otherwise." + }, + "page": { + "type": "integer", + "maximum": 9007199254740991, + "minimum": 1 + }, + "kind": { + "type": "string", + "enum": [ + "correct", + "formula", + "chart_figure", + "reading_order", + "headers_footers", + "headings_formatting", + "images_dropped" + ] + } + }, + "required": [ + "detail", + "basis", + "kind" + ], + "additionalProperties": false, + "title": "correct / formula / chart_figure / reading_order / headers_footers / headings_formatting / images_dropped", + "anyOf": [ + { + "properties": { + "basis": { + "enum": [ + "output", + "expectation" + ] + } + } + }, + { + "required": [ + "comparison" + ] + } + ] + }, + { + "type": "object", + "properties": { + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + }, + "basis": { + "type": "string", + "enum": [ + "output", + "source_comparison", + "expectation" + ], + "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + }, + "comparison": { + "type": "object", + "properties": { + "reference": { + "type": "string", + "minLength": 1, + "maxLength": 2048 + }, + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + } + }, + "required": [ + "reference", + "detail" + ], + "additionalProperties": false + }, + "format": { + "type": "string", + "minLength": 1, + "description": "A format type requested by the job. Required for output and source_comparison observations when multiple formats were requested; optional otherwise." + }, + "page": { + "type": "integer", + "maximum": 9007199254740991, + "minimum": 1 + }, + "kind": { + "type": "string", + "enum": [ + "text_ocr" + ] + }, + "reason": { + "type": "string", + "enum": [ + "misread_chars", + "garbled", + "missing_text" + ] + } + }, + "required": [ + "detail", + "basis", + "kind", + "reason" + ], + "additionalProperties": false, + "title": "text_ocr", + "anyOf": [ + { + "properties": { + "basis": { + "enum": [ + "output", + "expectation" + ] + } + } + }, + { + "required": [ + "comparison" + ] + } + ] + }, + { + "type": "object", + "properties": { + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + }, + "basis": { + "type": "string", + "enum": [ + "output", + "source_comparison", + "expectation" + ], + "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + }, + "comparison": { + "type": "object", + "properties": { + "reference": { + "type": "string", + "minLength": 1, + "maxLength": 2048 + }, + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + } + }, + "required": [ + "reference", + "detail" + ], + "additionalProperties": false + }, + "format": { + "type": "string", + "minLength": 1, + "description": "A format type requested by the job. Required for output and source_comparison observations when multiple formats were requested; optional otherwise." + }, + "page": { + "type": "integer", + "maximum": 9007199254740991, + "minimum": 1 + }, + "kind": { + "type": "string", + "enum": [ + "table" + ] + }, + "reason": { + "type": "string", + "enum": [ + "structure", + "cells_glued", + "digits" + ] + } + }, + "required": [ + "detail", + "basis", + "kind", + "reason" + ], + "additionalProperties": false, + "title": "table", + "anyOf": [ + { + "properties": { + "basis": { + "enum": [ + "output", + "expectation" + ] + } + } + }, + { + "required": [ + "comparison" + ] + } + ] + }, + { + "type": "object", + "properties": { + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + }, + "basis": { + "type": "string", + "enum": [ + "output", + "source_comparison", + "expectation" + ], + "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + }, + "comparison": { + "type": "object", + "properties": { + "reference": { + "type": "string", + "minLength": 1, + "maxLength": 2048 + }, + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + } + }, + "required": [ + "reference", + "detail" + ], + "additionalProperties": false + }, + "format": { + "type": "string", + "minLength": 1, + "description": "A format type requested by the job. Required for output and source_comparison observations when multiple formats were requested; optional otherwise." + }, + "page": { + "type": "integer", + "maximum": 9007199254740991, + "minimum": 1 + }, + "kind": { + "type": "string", + "enum": [ + "completeness" + ] + }, + "reason": { + "type": "string", + "enum": [ + "pages_missing", + "truncated_at_max_pages", + "sections_dropped" + ] + } + }, + "required": [ + "detail", + "basis", + "kind", + "reason" + ], + "additionalProperties": false, + "title": "completeness", + "anyOf": [ + { + "properties": { + "basis": { + "enum": [ + "output", + "expectation" + ] + } + } + }, + { + "required": [ + "comparison" + ] + } + ] + }, + { + "type": "object", + "properties": { + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + }, + "basis": { + "type": "string", + "enum": [ + "output", + "source_comparison", + "expectation" + ], + "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + }, + "comparison": { + "type": "object", + "properties": { + "reference": { + "type": "string", + "minLength": 1, + "maxLength": 2048 + }, + "detail": { + "type": "string", + "minLength": 10, + "maxLength": 2000 + } + }, + "required": [ + "reference", + "detail" + ], + "additionalProperties": false + }, + "format": { + "type": "string", + "minLength": 1, + "description": "A format type requested by the job. Required for output and source_comparison observations when multiple formats were requested; optional otherwise." + }, + "page": { + "type": "integer", + "maximum": 9007199254740991, + "minimum": 1 + }, + "kind": { + "type": "string", + "enum": [ + "incorrect" + ] + }, + "reason": { + "type": "string", + "enum": [ + "wrong", + "hallucinated", + "missing_fields" + ] + } + }, + "required": [ + "detail", + "basis", + "kind", + "reason" + ], + "additionalProperties": false, + "title": "incorrect", + "anyOf": [ + { + "properties": { + "basis": { + "enum": [ + "output", + "expectation" + ] + } + } + }, + { + "required": [ + "comparison" + ] + } + ] + } + ] + } + } + }, + "required": [ + "jobId", + "rating", + "task", + "assessment", + "endpoint", + "docClass", + "observations" + ], + "additionalProperties": false, + "title": "Keyless Parse" + } + ], + "description": "Optional evidence for a keyless Search, Scrape, or Parse job. Strings are trimmed before validation. Use observations already available from the task; distinguish returned output, source comparisons, and unmet expectations." } } }, From d92af053d6a32a6326849c7758bde1023421aa90 Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Sun, 13 Sep 2026 15:47:23 -0500 Subject: [PATCH 02/25] docs(api): clarify feedback authentication and evidence options --- api-reference/endpoint/feedback.mdx | 4 + api-reference/v2-openapi.json | 156 +++++++++++++++++++++++----- 2 files changed, 136 insertions(+), 24 deletions(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index 9900ee73a..34b8c0c7a 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -6,6 +6,10 @@ openapi: '/api-reference/v2-openapi.json POST /feedback' Use endpoint feedback to tell Firecrawl whether a job result met your task's needs. + +For keyless jobs, omit the `Authorization` header and choose the matching keyless request format. For authenticated jobs, send your API key and use the authenticated request format. + + ## Keyless feedback Eligible keyless callers submit optional evidence through `POST /v2/feedback`. Search, Scrape, and Parse use the same identity and submission limits across API, MCP, and CLI. An API key is not required. The authenticated feedback routes keep their existing request contracts. diff --git a/api-reference/v2-openapi.json b/api-reference/v2-openapi.json index 5e6b0452a..971ea6e46 100644 --- a/api-reference/v2-openapi.json +++ b/api-reference/v2-openapi.json @@ -11947,12 +11947,21 @@ "expectation" ] } - } + }, + "title": "useful (output or expectation)" }, { "required": [ "comparison" - ] + ], + "title": "useful (source comparison)", + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] + } + } } ] }, @@ -12058,12 +12067,21 @@ "expectation" ] } - } + }, + "title": "irrelevant (output or expectation)" }, { "required": [ "comparison" - ] + ], + "title": "irrelevant (source comparison)", + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] + } + } } ] }, @@ -12156,12 +12174,21 @@ "expectation" ] } - } + }, + "title": "missing (output or expectation)" }, { "required": [ "comparison" - ] + ], + "title": "missing (source comparison)", + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] + } + } } ] } @@ -12299,12 +12326,21 @@ "expectation" ] } - } + }, + "title": "correct (output or expectation)" }, { "required": [ "comparison" - ] + ], + "title": "correct (source comparison)", + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] + } + } } ] }, @@ -12391,12 +12427,21 @@ "expectation" ] } - } + }, + "title": "wrong_success (output or expectation)" }, { "required": [ "comparison" - ] + ], + "title": "wrong_success (source comparison)", + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] + } + } } ] }, @@ -12481,12 +12526,21 @@ "expectation" ] } - } + }, + "title": "incomplete (output or expectation)" }, { "required": [ "comparison" - ] + ], + "title": "incomplete (source comparison)", + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] + } + } } ] }, @@ -12569,12 +12623,21 @@ "expectation" ] } - } + }, + "title": "incorrect (output or expectation)" }, { "required": [ "comparison" - ] + ], + "title": "incorrect (source comparison)", + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] + } + } } ] } @@ -12728,12 +12791,21 @@ "expectation" ] } - } + }, + "title": "correct / formula / chart_figure / reading_order / headers_footers / headings_formatting / images_dropped (output or expectation)" }, { "required": [ "comparison" - ] + ], + "title": "correct / formula / chart_figure / reading_order / headers_footers / headings_formatting / images_dropped (source comparison)", + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] + } + } } ] }, @@ -12816,12 +12888,21 @@ "expectation" ] } - } + }, + "title": "text_ocr (output or expectation)" }, { "required": [ "comparison" - ] + ], + "title": "text_ocr (source comparison)", + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] + } + } } ] }, @@ -12904,12 +12985,21 @@ "expectation" ] } - } + }, + "title": "table (output or expectation)" }, { "required": [ "comparison" - ] + ], + "title": "table (source comparison)", + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] + } + } } ] }, @@ -12992,12 +13082,21 @@ "expectation" ] } - } + }, + "title": "completeness (output or expectation)" }, { "required": [ "comparison" - ] + ], + "title": "completeness (source comparison)", + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] + } + } } ] }, @@ -13080,12 +13179,21 @@ "expectation" ] } - } + }, + "title": "incorrect (output or expectation)" }, { "required": [ "comparison" - ] + ], + "title": "incorrect (source comparison)", + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] + } + } } ] } From a2893cb503644008742adf64e28a09da62bbce0a Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Sun, 13 Sep 2026 15:51:13 -0500 Subject: [PATCH 03/25] docs(api): simplify the keyless feedback example --- api-reference/endpoint/feedback.mdx | 12 +-- api-reference/v2-openapi.json | 156 +++++----------------------- 2 files changed, 26 insertions(+), 142 deletions(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index 34b8c0c7a..2a5c2070e 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -30,9 +30,9 @@ Scrape and Parse: format must be a format type the job requested. It is required { "endpoint": "search", "jobId": "00000000-0000-4000-8000-000000000001", - "rating": "partial", + "rating": "good", "task": "Find the documented retry behavior", - "assessment": "The API reference answered the retry question, but the news result did not.", + "assessment": "The API reference answered the retry question.", "observations": [ { "kind": "useful", @@ -40,14 +40,6 @@ Scrape and Parse: format must be a format type the job requested. It is required "position": 1, "basis": "output", "detail": "The reference specifies the retry intervals." - }, - { - "kind": "irrelevant", - "reason": "off_topic", - "source": "news", - "position": 1, - "basis": "output", - "detail": "The announcement does not discuss retry behavior." } ] } diff --git a/api-reference/v2-openapi.json b/api-reference/v2-openapi.json index 971ea6e46..5e6b0452a 100644 --- a/api-reference/v2-openapi.json +++ b/api-reference/v2-openapi.json @@ -11947,21 +11947,12 @@ "expectation" ] } - }, - "title": "useful (output or expectation)" + } }, { "required": [ "comparison" - ], - "title": "useful (source comparison)", - "properties": { - "basis": { - "enum": [ - "source_comparison" - ] - } - } + ] } ] }, @@ -12067,21 +12058,12 @@ "expectation" ] } - }, - "title": "irrelevant (output or expectation)" + } }, { "required": [ "comparison" - ], - "title": "irrelevant (source comparison)", - "properties": { - "basis": { - "enum": [ - "source_comparison" - ] - } - } + ] } ] }, @@ -12174,21 +12156,12 @@ "expectation" ] } - }, - "title": "missing (output or expectation)" + } }, { "required": [ "comparison" - ], - "title": "missing (source comparison)", - "properties": { - "basis": { - "enum": [ - "source_comparison" - ] - } - } + ] } ] } @@ -12326,21 +12299,12 @@ "expectation" ] } - }, - "title": "correct (output or expectation)" + } }, { "required": [ "comparison" - ], - "title": "correct (source comparison)", - "properties": { - "basis": { - "enum": [ - "source_comparison" - ] - } - } + ] } ] }, @@ -12427,21 +12391,12 @@ "expectation" ] } - }, - "title": "wrong_success (output or expectation)" + } }, { "required": [ "comparison" - ], - "title": "wrong_success (source comparison)", - "properties": { - "basis": { - "enum": [ - "source_comparison" - ] - } - } + ] } ] }, @@ -12526,21 +12481,12 @@ "expectation" ] } - }, - "title": "incomplete (output or expectation)" + } }, { "required": [ "comparison" - ], - "title": "incomplete (source comparison)", - "properties": { - "basis": { - "enum": [ - "source_comparison" - ] - } - } + ] } ] }, @@ -12623,21 +12569,12 @@ "expectation" ] } - }, - "title": "incorrect (output or expectation)" + } }, { "required": [ "comparison" - ], - "title": "incorrect (source comparison)", - "properties": { - "basis": { - "enum": [ - "source_comparison" - ] - } - } + ] } ] } @@ -12791,21 +12728,12 @@ "expectation" ] } - }, - "title": "correct / formula / chart_figure / reading_order / headers_footers / headings_formatting / images_dropped (output or expectation)" + } }, { "required": [ "comparison" - ], - "title": "correct / formula / chart_figure / reading_order / headers_footers / headings_formatting / images_dropped (source comparison)", - "properties": { - "basis": { - "enum": [ - "source_comparison" - ] - } - } + ] } ] }, @@ -12888,21 +12816,12 @@ "expectation" ] } - }, - "title": "text_ocr (output or expectation)" + } }, { "required": [ "comparison" - ], - "title": "text_ocr (source comparison)", - "properties": { - "basis": { - "enum": [ - "source_comparison" - ] - } - } + ] } ] }, @@ -12985,21 +12904,12 @@ "expectation" ] } - }, - "title": "table (output or expectation)" + } }, { "required": [ "comparison" - ], - "title": "table (source comparison)", - "properties": { - "basis": { - "enum": [ - "source_comparison" - ] - } - } + ] } ] }, @@ -13082,21 +12992,12 @@ "expectation" ] } - }, - "title": "completeness (output or expectation)" + } }, { "required": [ "comparison" - ], - "title": "completeness (source comparison)", - "properties": { - "basis": { - "enum": [ - "source_comparison" - ] - } - } + ] } ] }, @@ -13179,21 +13080,12 @@ "expectation" ] } - }, - "title": "incorrect (output or expectation)" + } }, { "required": [ "comparison" - ], - "title": "incorrect (source comparison)", - "properties": { - "basis": { - "enum": [ - "source_comparison" - ] - } - } + ] } ] } From 8d6d8d906a00cbfc7cda9baaccfaaca9be2e8c2c Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Sun, 13 Sep 2026 15:57:28 -0500 Subject: [PATCH 04/25] docs: simplify feedback page naming --- api-reference/endpoint/feedback.mdx | 6 +++--- api-reference/endpoint/parse.mdx | 2 +- api-reference/endpoint/scrape.mdx | 2 +- api-reference/endpoint/search.mdx | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index 2a5c2070e..8d82774cd 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -1,10 +1,10 @@ --- -title: 'Endpoint Feedback' -description: 'Submit feedback for a v2 endpoint job.' +title: 'Feedback' +description: 'Share feedback on a Firecrawl job.' openapi: '/api-reference/v2-openapi.json POST /feedback' --- -Use endpoint feedback to tell Firecrawl whether a job result met your task's needs. +Share what worked and what needs improvement. For keyless jobs, omit the `Authorization` header and choose the matching keyless request format. For authenticated jobs, send your API key and use the authenticated request format. diff --git a/api-reference/endpoint/parse.mdx b/api-reference/endpoint/parse.mdx index 286d6187d..91e085482 100644 --- a/api-reference/endpoint/parse.mdx +++ b/api-reference/endpoint/parse.mdx @@ -25,4 +25,4 @@ Use `/parse` when the source document is **a local file** or **not publicly acce ## Optional keyless feedback -Eligible keyless responses may include an invitation to submit [endpoint feedback](/api-reference/endpoint/feedback). Use the returned `jobId` and observations already available from your task. Submitting feedback is optional. +Eligible keyless responses may include an invitation to submit [feedback](/api-reference/endpoint/feedback). Use the returned `jobId` and observations already available from your task. Submitting feedback is optional. diff --git a/api-reference/endpoint/scrape.mdx b/api-reference/endpoint/scrape.mdx index e7ee84814..40d8cf75c 100644 --- a/api-reference/endpoint/scrape.mdx +++ b/api-reference/endpoint/scrape.mdx @@ -19,4 +19,4 @@ Optionally you can also use the `actions` parameter, although it's not recommend ## Optional keyless feedback -Eligible keyless responses may include an invitation to submit [endpoint feedback](/api-reference/endpoint/feedback). Use the returned `jobId` and observations already available from your task. Submitting feedback is optional. +Eligible keyless responses may include an invitation to submit [feedback](/api-reference/endpoint/feedback). Use the returned `jobId` and observations already available from your task. Submitting feedback is optional. diff --git a/api-reference/endpoint/search.mdx b/api-reference/endpoint/search.mdx index 785ffa749..09ca4c452 100644 --- a/api-reference/endpoint/search.mdx +++ b/api-reference/endpoint/search.mdx @@ -127,4 +127,4 @@ Use the `tbs` parameter to filter results by time periods, including custom date ## Optional keyless feedback -Eligible keyless responses may include an invitation to submit [endpoint feedback](/api-reference/endpoint/feedback). Use the returned `id` and observations already available from your task. Submitting feedback is optional. +Eligible keyless responses may include an invitation to submit [feedback](/api-reference/endpoint/feedback). Use the returned `id` and observations already available from your task. Submitting feedback is optional. From 2ea3c84c2a65de05307db40f4b3bf19c8ec3cb98 Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Sun, 13 Sep 2026 15:59:25 -0500 Subject: [PATCH 05/25] docs: streamline feedback submission guidance --- api-reference/endpoint/feedback.mdx | 76 ++++++++++------------------- 1 file changed, 27 insertions(+), 49 deletions(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index 8d82774cd..4c122baf9 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -6,66 +6,44 @@ openapi: '/api-reference/v2-openapi.json POST /feedback' Share what worked and what needs improvement. - -For keyless jobs, omit the `Authorization` header and choose the matching keyless request format. For authenticated jobs, send your API key and use the authenticated request format. - - ## Keyless feedback -Eligible keyless callers submit optional evidence through `POST /v2/feedback`. Search, Scrape, and Parse use the same identity and submission limits across API, MCP, and CLI. An API key is not required. The authenticated feedback routes keep their existing request contracts. - -A submission requires `endpoint`, `jobId`, `rating` (`good`, `partial`, or `bad`), `task`, `assessment`, and 1-20 `observations`. Task, assessment, and observation detail must each contain 10-2000 characters after trimming. These bounds reject empty or very short answers; they cannot guarantee factual accuracy. - -Each observation requires `kind`, `detail`, and `basis`. Use `output` for observations about returned content, `source_comparison` for comparisons already made, and `expectation` for unmet expectations that have not been verified against a source. A source comparison requires `comparison: {reference, detail}`. Do not guess missing content, diagnose root causes, or investigate solely to submit feedback. Unmentioned results are unassessed. - -Search: useful and irrelevant require a one-based position within the delivered group. source names the response group the position refers to: web, images, or news. It is required only when the job requested multiple sources; otherwise it defaults to web. The position must exist in that requested group. irrelevant requires reason: aggregator_over_official, off_topic, stale, wrong_content_type, snippet_misleading, or blocked_or_paywalled. vertical is required on missing and optional on useful/irrelevant: web_general, social, business, research, developer, news, government, finance, or other. missing may include topic (up to 200 characters) and knownSources (up to 20 HTTP(S) URLs). Do not submit engine attribution; it comes from the stored category tag at that position. +Submit optional feedback for a Search, Scrape, or Parse job using its returned job ID. One submission is accepted per keyless identity per UTC day, shared across all three endpoints and clients. -Scrape: kind correct, wrong_success, incomplete, or incorrect. wrong_success requires reason: blocked_shell, login_required, paywall, empty, wrong_page, stale, or wrong_locale. incomplete requires reason: partial_content, dynamic_content, pagination, main_content_stripped, or format_lost. incorrect requires reason: wrong, hallucinated, or missing_fields. correct has no reason. Optional location is up to 200 characters. No retryOutcome. Hard-failed Scrape jobs receive no feedback invitation. + +Omit the `Authorization` header for keyless jobs. Select the matching keyless request format in the reference below. + -Parse: docClass is required once per submission: born_digital, scanned, mixed, or unknown. Observation kind: correct, text_ocr, table, formula, chart_figure, reading_order, headers_footers, headings_formatting, completeness, images_dropped, or incorrect. text_ocr requires reason: misread_chars, garbled, or missing_text. table requires reason: structure, cells_glued, or digits. completeness requires reason: pages_missing, truncated_at_max_pages, or sections_dropped. incorrect requires reason: wrong, hallucinated, or missing_fields. Other kinds have no reason subtype. Optional page is a one-based positive integer. +Describe your task and include specific observations using information already available to you. Use `basis: "output"` for returned content, `"source_comparison"` with `comparison` for a source you already inspected, or `"expectation"` for an unmet need. -Scrape and Parse: format must be a format type the job requested. It is required for output and source_comparison observations when multiple formats were requested; optional for expectation observations and single-format jobs. All observations retain detail and basis; source_comparison requires `comparison: {reference, detail}`. +### Example request -```json -{ - "endpoint": "search", - "jobId": "00000000-0000-4000-8000-000000000001", - "rating": "good", - "task": "Find the documented retry behavior", - "assessment": "The API reference answered the retry question.", - "observations": [ - { - "kind": "useful", - "source": "web", - "position": 1, - "basis": "output", - "detail": "The reference specifies the retry intervals." - } - ] -} +```bash +curl -X POST "https://api.firecrawl.dev/v2/feedback" \ + -H "Content-Type: application/json" \ + -d '{ + "endpoint": "search", + "jobId": "00000000-0000-4000-8000-000000000001", + "rating": "good", + "task": "Find the documented retry behavior", + "assessment": "The API reference answered the retry question.", + "observations": [ + { + "kind": "useful", + "source": "web", + "position": 1, + "basis": "output", + "detail": "The reference specifies the retry intervals." + } + ] + }' ``` -## Discovery and clients - -Search returns its `id` and optional top-level `metadata`. Scrape and Parse include `jobId` and optional `feedback` in `data.metadata`. Execution failures can include top-level `metadata`. Submit feedback using the job reference returned for the same caller and endpoint. - -MCP exposes `firecrawl_feedback`. CLI exposes `firecrawl feedback --rating --task --assessment --observations-file `. Parse submissions also require `docClass`, passed as `--doc-class` in CLI. CLI invitations use stderr, preserving ordinary stdout; JSON results retain metadata. - -Eligible responses may include an optional invitation to submit feedback. Submissions remain optional and are never required for continued keyless access. - -## Submission behavior - -One new submission is accepted per keyless identity per UTC day, shared across Search, Scrape, Parse, and all clients. A retry for the same eligible job returns the original feedback ID with `alreadySubmitted: true`. Feedback does not consume or restore operation allowance. - -A job may no longer be eligible when feedback is submitted. - -Accepted feedback is stored with the originating request options and available result context. Jobs that disallow data retention are excluded. - ## Authenticated feedback -When using an API key, keep using the existing endpoint feedback fields for `scrape`, `parse`, `map`, and `search`. For authenticated Search jobs, [Search Feedback](/api-reference/endpoint/search-feedback) remains the search-specific entry point. Its request format and refund behavior are unchanged. +For jobs created with an API key, use the authenticated request format and include your key. For authenticated Search jobs, [Search Feedback](/api-reference/endpoint/search-feedback) is the preferred search-specific entry point. -### Example request with an API key +### Example request ```bash curl -X POST "https://api.firecrawl.dev/v2/feedback" \ From ab633ec1cb527cb2961d271ee8a321fc1ec15de8 Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Sun, 13 Sep 2026 16:03:11 -0500 Subject: [PATCH 06/25] docs: align feedback descriptions with API behavior --- api-reference/v2-openapi.json | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/api-reference/v2-openapi.json b/api-reference/v2-openapi.json index 5e6b0452a..cc25365ea 100644 --- a/api-reference/v2-openapi.json +++ b/api-reference/v2-openapi.json @@ -6058,7 +6058,7 @@ } }, "403": { - "description": "Feedback is not available for this team", + "description": "Feedback is not available for this caller", "content": { "application/json": { "schema": { @@ -6068,7 +6068,7 @@ } }, "404": { - "description": "Job not found for this team", + "description": "No eligible job found for this caller and endpoint", "content": { "application/json": { "schema": { @@ -6116,9 +6116,19 @@ } } } + }, + "401": { + "description": "Authentication failed or keyless access is unavailable", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeedbackErrorResponse" + } + } + } } }, - "description": "Submit optional feedback for a Search, Scrape, or Parse job. Keyless callers use KeylessFeedbackRequest and may submit once per identity per UTC day, shared across all three categories and clients. Authenticated callers continue to use EndpointFeedbackRequest." + "description": "Submit optional feedback for a v2 job. Keyless callers can submit Search, Scrape, or Parse feedback once per identity per UTC day, shared across all three categories and clients. Authenticated callers use EndpointFeedbackRequest for Search, Scrape, Parse, or Map jobs." } }, "/team/threat-protection": { @@ -13106,7 +13116,7 @@ "title": "Keyless Parse" } ], - "description": "Optional evidence for a keyless Search, Scrape, or Parse job. Strings are trimmed before validation. Use observations already available from the task; distinguish returned output, source comparisons, and unmet expectations." + "description": "Optional evidence for a keyless Search, Scrape, or Parse job. Text length limits apply after trimming leading and trailing whitespace. Use observations already available from the task; distinguish returned output, source comparisons, and unmet expectations." } } }, From 711757f00bd3d46e893ad761ec77ad112f4a20c7 Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Sun, 13 Sep 2026 16:41:16 -0500 Subject: [PATCH 07/25] docs: clarify optional feedback authentication --- api-reference/endpoint/feedback.mdx | 20 +++++++++++--------- api-reference/v2-openapi.json | 7 ++++++- style.css | 6 ++++++ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index 4c122baf9..c7f5305aa 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -10,15 +10,21 @@ Share what worked and what needs improvement. Submit optional feedback for a Search, Scrape, or Parse job using its returned job ID. One submission is accepted per keyless identity per UTC day, shared across all three endpoints and clients. +
Omit the `Authorization` header for keyless jobs. Select the matching keyless request format in the reference below. +
Describe your task and include specific observations using information already available to you. Use `basis: "output"` for returned content, `"source_comparison"` with `comparison` for a source you already inspected, or `"expectation"` for an unmet need. -### Example request +## Authenticated feedback + +For jobs created with an API key, use the authenticated request format and include your key. For authenticated Search jobs, [Search Feedback](/api-reference/endpoint/search-feedback) is the preferred search-specific entry point. -```bash + + +```bash Keyless feedback curl -X POST "https://api.firecrawl.dev/v2/feedback" \ -H "Content-Type: application/json" \ -d '{ @@ -39,13 +45,7 @@ curl -X POST "https://api.firecrawl.dev/v2/feedback" \ }' ``` -## Authenticated feedback - -For jobs created with an API key, use the authenticated request format and include your key. For authenticated Search jobs, [Search Feedback](/api-reference/endpoint/search-feedback) is the preferred search-specific entry point. - -### Example request - -```bash +```bash Authenticated feedback curl -X POST "https://api.firecrawl.dev/v2/feedback" \ -H "Authorization: Bearer $FIRECRAWL_API_KEY" \ -H "Content-Type: application/json" \ @@ -58,3 +58,5 @@ curl -X POST "https://api.firecrawl.dev/v2/feedback" \ "url": "https://example.com/pricing" }' ``` + + diff --git a/api-reference/v2-openapi.json b/api-reference/v2-openapi.json index cc25365ea..9a5695f05 100644 --- a/api-reference/v2-openapi.json +++ b/api-reference/v2-openapi.json @@ -6011,7 +6011,7 @@ "security": [ {}, { - "bearerAuth": [] + "feedbackBearerAuth": [] } ], "requestBody": { @@ -6434,6 +6434,11 @@ "bearerAuth": { "type": "http", "scheme": "bearer" + }, + "feedbackBearerAuth": { + "type": "http", + "scheme": "bearer", + "description": "Required only for jobs created with an API key. Send `Bearer ` for authenticated feedback. Omit this header for keyless feedback." } }, "parameters": { diff --git a/style.css b/style.css index ab52226bf..c47e3f012 100644 --- a/style.css +++ b/style.css @@ -710,3 +710,9 @@ a > div.w-full > div.mt-8 { transition-duration: 0.01ms !important; } } + +/* Mintlify marks optional bearer auth required. Scope the correction to Feedback. */ +body:has(#feedback-auth-guidance) #authorization-authorization [data-component-part="field-required-pill"], +body:has(#feedback-auth-guidance) [data-testid="api-input-Authorization"] [data-component-part="field-required-pill"] { + display: none; +} From 9a5e507a34762adbadea4c88e7fa277f82e85739 Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Sun, 13 Sep 2026 16:56:47 -0500 Subject: [PATCH 08/25] docs: restore inline feedback examples --- api-reference/endpoint/feedback.mdx | 20 +++++++++----------- style.css | 6 ------ 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index c7f5305aa..4c122baf9 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -10,21 +10,15 @@ Share what worked and what needs improvement. Submit optional feedback for a Search, Scrape, or Parse job using its returned job ID. One submission is accepted per keyless identity per UTC day, shared across all three endpoints and clients. -
Omit the `Authorization` header for keyless jobs. Select the matching keyless request format in the reference below. -
Describe your task and include specific observations using information already available to you. Use `basis: "output"` for returned content, `"source_comparison"` with `comparison` for a source you already inspected, or `"expectation"` for an unmet need. -## Authenticated feedback - -For jobs created with an API key, use the authenticated request format and include your key. For authenticated Search jobs, [Search Feedback](/api-reference/endpoint/search-feedback) is the preferred search-specific entry point. +### Example request - - -```bash Keyless feedback +```bash curl -X POST "https://api.firecrawl.dev/v2/feedback" \ -H "Content-Type: application/json" \ -d '{ @@ -45,7 +39,13 @@ curl -X POST "https://api.firecrawl.dev/v2/feedback" \ }' ``` -```bash Authenticated feedback +## Authenticated feedback + +For jobs created with an API key, use the authenticated request format and include your key. For authenticated Search jobs, [Search Feedback](/api-reference/endpoint/search-feedback) is the preferred search-specific entry point. + +### Example request + +```bash curl -X POST "https://api.firecrawl.dev/v2/feedback" \ -H "Authorization: Bearer $FIRECRAWL_API_KEY" \ -H "Content-Type: application/json" \ @@ -58,5 +58,3 @@ curl -X POST "https://api.firecrawl.dev/v2/feedback" \ "url": "https://example.com/pricing" }' ``` - - diff --git a/style.css b/style.css index c47e3f012..ab52226bf 100644 --- a/style.css +++ b/style.css @@ -710,9 +710,3 @@ a > div.w-full > div.mt-8 { transition-duration: 0.01ms !important; } } - -/* Mintlify marks optional bearer auth required. Scope the correction to Feedback. */ -body:has(#feedback-auth-guidance) #authorization-authorization [data-component-part="field-required-pill"], -body:has(#feedback-auth-guidance) [data-testid="api-input-Authorization"] [data-component-part="field-required-pill"] { - display: none; -} From 2f07b99383987f06511abb355e2451c7a27a754d Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Sun, 13 Sep 2026 17:25:17 -0500 Subject: [PATCH 09/25] docs: shorten feedback request tabs --- api-reference/endpoint/feedback.mdx | 4 ++-- api-reference/v2-openapi.json | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index 4c122baf9..a4ed0aa7e 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -11,7 +11,7 @@ Share what worked and what needs improvement. Submit optional feedback for a Search, Scrape, or Parse job using its returned job ID. One submission is accepted per keyless identity per UTC day, shared across all three endpoints and clients. -Omit the `Authorization` header for keyless jobs. Select the matching keyless request format in the reference below. +For keyless jobs, omit the `Authorization` header and select Search, Scrape, or Parse in the reference below. Describe your task and include specific observations using information already available to you. Use `basis: "output"` for returned content, `"source_comparison"` with `comparison` for a source you already inspected, or `"expectation"` for an unmet need. @@ -41,7 +41,7 @@ curl -X POST "https://api.firecrawl.dev/v2/feedback" \ ## Authenticated feedback -For jobs created with an API key, use the authenticated request format and include your key. For authenticated Search jobs, [Search Feedback](/api-reference/endpoint/search-feedback) is the preferred search-specific entry point. +For jobs created with an API key, select Authenticated in the reference below and include your key. For authenticated Search jobs, [Search Feedback](/api-reference/endpoint/search-feedback) is the preferred search-specific entry point. ### Example request diff --git a/api-reference/v2-openapi.json b/api-reference/v2-openapi.json index 9a5695f05..e3b2c553b 100644 --- a/api-reference/v2-openapi.json +++ b/api-reference/v2-openapi.json @@ -6024,7 +6024,7 @@ "$ref": "#/components/schemas/KeylessFeedbackRequest" }, { - "title": "Authenticated feedback", + "title": "Authenticated", "allOf": [ { "$ref": "#/components/schemas/EndpointFeedbackRequest" @@ -12193,7 +12193,7 @@ "observations" ], "additionalProperties": false, - "title": "Keyless Search" + "title": "Search" }, { "type": "object", @@ -12606,7 +12606,7 @@ "observations" ], "additionalProperties": false, - "title": "Keyless Scrape" + "title": "Scrape" }, { "type": "object", @@ -13118,7 +13118,7 @@ "observations" ], "additionalProperties": false, - "title": "Keyless Parse" + "title": "Parse" } ], "description": "Optional evidence for a keyless Search, Scrape, or Parse job. Text length limits apply after trimming leading and trailing whitespace. Use observations already available from the task; distinguish returned output, source comparisons, and unmet expectations." From 5fa1e983184cbefa59b350d5cd65b68656930957 Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Sun, 13 Sep 2026 20:28:00 -0500 Subject: [PATCH 10/25] docs: minimize feedback guidance and reuse evidence definitions --- api-reference/endpoint/feedback.mdx | 18 +- api-reference/v2-openapi.json | 438 +++++----------------------- 2 files changed, 83 insertions(+), 373 deletions(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index a4ed0aa7e..44dded8c1 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -6,17 +6,11 @@ openapi: '/api-reference/v2-openapi.json POST /feedback' Share what worked and what needs improvement. -## Keyless feedback +For keyless Search, Scrape, or Parse jobs, omit `Authorization` and select the matching request format below. Use the job ID returned by the operation. One submission is accepted per keyless identity per UTC day, shared across endpoints and clients. -Submit optional feedback for a Search, Scrape, or Parse job using its returned job ID. One submission is accepted per keyless identity per UTC day, shared across all three endpoints and clients. +For jobs created with an API key, include your key and select Authenticated below. [Search Feedback](/api-reference/endpoint/search-feedback) remains the preferred entry point for authenticated Search jobs. - -For keyless jobs, omit the `Authorization` header and select Search, Scrape, or Parse in the reference below. - - -Describe your task and include specific observations using information already available to you. Use `basis: "output"` for returned content, `"source_comparison"` with `comparison` for a source you already inspected, or `"expectation"` for an unmet need. - -### Example request +### Keyless example ```bash curl -X POST "https://api.firecrawl.dev/v2/feedback" \ @@ -39,11 +33,7 @@ curl -X POST "https://api.firecrawl.dev/v2/feedback" \ }' ``` -## Authenticated feedback - -For jobs created with an API key, select Authenticated in the reference below and include your key. For authenticated Search jobs, [Search Feedback](/api-reference/endpoint/search-feedback) is the preferred search-specific entry point. - -### Example request +### Authenticated example ```bash curl -X POST "https://api.firecrawl.dev/v2/feedback" \ diff --git a/api-reference/v2-openapi.json b/api-reference/v2-openapi.json index e3b2c553b..3ec32966c 100644 --- a/api-reference/v2-openapi.json +++ b/api-reference/v2-openapi.json @@ -6128,7 +6128,7 @@ } } }, - "description": "Submit optional feedback for a v2 job. Keyless callers can submit Search, Scrape, or Parse feedback once per identity per UTC day, shared across all three categories and clients. Authenticated callers use EndpointFeedbackRequest for Search, Scrape, Parse, or Map jobs." + "description": "Submit optional feedback for a job. Keyless requests support Search, Scrape, and Parse. Authenticated requests also support Map." } }, "/team/threat-protection": { @@ -6438,7 +6438,7 @@ "feedbackBearerAuth": { "type": "http", "scheme": "bearer", - "description": "Required only for jobs created with an API key. Send `Bearer ` for authenticated feedback. Omit this header for keyless feedback." + "description": "For authenticated jobs, send `Bearer `. Omit this header for keyless jobs." } }, "parameters": { @@ -11841,14 +11841,10 @@ ] }, "task": { - "type": "string", - "minLength": 10, - "maxLength": 2000 + "$ref": "#/components/schemas/KeylessFeedbackDetail" }, "assessment": { - "type": "string", - "minLength": 10, - "maxLength": 2000 + "$ref": "#/components/schemas/KeylessFeedbackDetail" }, "origin": { "default": "api", @@ -11876,38 +11872,13 @@ "type": "object", "properties": { "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 + "$ref": "#/components/schemas/KeylessFeedbackDetail" }, "basis": { - "type": "string", - "enum": [ - "output", - "source_comparison", - "expectation" - ], - "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + "$ref": "#/components/schemas/KeylessFeedbackBasis" }, "comparison": { - "type": "object", - "properties": { - "reference": { - "type": "string", - "minLength": 1, - "maxLength": 2048 - }, - "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 - } - }, - "required": [ - "reference", - "detail" - ], - "additionalProperties": false + "$ref": "#/components/schemas/KeylessFeedbackComparison" }, "source": { "type": "string", @@ -11921,7 +11892,7 @@ "position": { "type": "integer", "maximum": 9007199254740991, - "description": "One-based position within the delivered response group. Engine attribution comes from the stored category tag at that position.", + "description": "One-based position within the delivered response group.", "minimum": 1 }, "vertical": { @@ -11975,38 +11946,13 @@ "type": "object", "properties": { "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 + "$ref": "#/components/schemas/KeylessFeedbackDetail" }, "basis": { - "type": "string", - "enum": [ - "output", - "source_comparison", - "expectation" - ], - "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + "$ref": "#/components/schemas/KeylessFeedbackBasis" }, "comparison": { - "type": "object", - "properties": { - "reference": { - "type": "string", - "minLength": 1, - "maxLength": 2048 - }, - "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 - } - }, - "required": [ - "reference", - "detail" - ], - "additionalProperties": false + "$ref": "#/components/schemas/KeylessFeedbackComparison" }, "source": { "type": "string", @@ -12020,7 +11966,7 @@ "position": { "type": "integer", "maximum": 9007199254740991, - "description": "One-based position within the delivered response group. Engine attribution comes from the stored category tag at that position.", + "description": "One-based position within the delivered response group.", "minimum": 1 }, "vertical": { @@ -12086,38 +12032,13 @@ "type": "object", "properties": { "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 + "$ref": "#/components/schemas/KeylessFeedbackDetail" }, "basis": { - "type": "string", - "enum": [ - "output", - "source_comparison", - "expectation" - ], - "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + "$ref": "#/components/schemas/KeylessFeedbackBasis" }, "comparison": { - "type": "object", - "properties": { - "reference": { - "type": "string", - "minLength": 1, - "maxLength": 2048 - }, - "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 - } - }, - "required": [ - "reference", - "detail" - ], - "additionalProperties": false + "$ref": "#/components/schemas/KeylessFeedbackComparison" }, "kind": { "type": "string", @@ -12213,14 +12134,10 @@ ] }, "task": { - "type": "string", - "minLength": 10, - "maxLength": 2000 + "$ref": "#/components/schemas/KeylessFeedbackDetail" }, "assessment": { - "type": "string", - "minLength": 10, - "maxLength": 2000 + "$ref": "#/components/schemas/KeylessFeedbackDetail" }, "origin": { "default": "api", @@ -12248,38 +12165,13 @@ "type": "object", "properties": { "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 + "$ref": "#/components/schemas/KeylessFeedbackDetail" }, "basis": { - "type": "string", - "enum": [ - "output", - "source_comparison", - "expectation" - ], - "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + "$ref": "#/components/schemas/KeylessFeedbackBasis" }, "comparison": { - "type": "object", - "properties": { - "reference": { - "type": "string", - "minLength": 1, - "maxLength": 2048 - }, - "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 - } - }, - "required": [ - "reference", - "detail" - ], - "additionalProperties": false + "$ref": "#/components/schemas/KeylessFeedbackComparison" }, "format": { "type": "string", @@ -12327,38 +12219,13 @@ "type": "object", "properties": { "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 + "$ref": "#/components/schemas/KeylessFeedbackDetail" }, "basis": { - "type": "string", - "enum": [ - "output", - "source_comparison", - "expectation" - ], - "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + "$ref": "#/components/schemas/KeylessFeedbackBasis" }, "comparison": { - "type": "object", - "properties": { - "reference": { - "type": "string", - "minLength": 1, - "maxLength": 2048 - }, - "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 - } - }, - "required": [ - "reference", - "detail" - ], - "additionalProperties": false + "$ref": "#/components/schemas/KeylessFeedbackComparison" }, "format": { "type": "string", @@ -12419,38 +12286,13 @@ "type": "object", "properties": { "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 + "$ref": "#/components/schemas/KeylessFeedbackDetail" }, "basis": { - "type": "string", - "enum": [ - "output", - "source_comparison", - "expectation" - ], - "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + "$ref": "#/components/schemas/KeylessFeedbackBasis" }, "comparison": { - "type": "object", - "properties": { - "reference": { - "type": "string", - "minLength": 1, - "maxLength": 2048 - }, - "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 - } - }, - "required": [ - "reference", - "detail" - ], - "additionalProperties": false + "$ref": "#/components/schemas/KeylessFeedbackComparison" }, "format": { "type": "string", @@ -12509,38 +12351,13 @@ "type": "object", "properties": { "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 + "$ref": "#/components/schemas/KeylessFeedbackDetail" }, "basis": { - "type": "string", - "enum": [ - "output", - "source_comparison", - "expectation" - ], - "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + "$ref": "#/components/schemas/KeylessFeedbackBasis" }, "comparison": { - "type": "object", - "properties": { - "reference": { - "type": "string", - "minLength": 1, - "maxLength": 2048 - }, - "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 - } - }, - "required": [ - "reference", - "detail" - ], - "additionalProperties": false + "$ref": "#/components/schemas/KeylessFeedbackComparison" }, "format": { "type": "string", @@ -12626,14 +12443,10 @@ ] }, "task": { - "type": "string", - "minLength": 10, - "maxLength": 2000 + "$ref": "#/components/schemas/KeylessFeedbackDetail" }, "assessment": { - "type": "string", - "minLength": 10, - "maxLength": 2000 + "$ref": "#/components/schemas/KeylessFeedbackDetail" }, "origin": { "default": "api", @@ -12671,38 +12484,13 @@ "type": "object", "properties": { "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 + "$ref": "#/components/schemas/KeylessFeedbackDetail" }, "basis": { - "type": "string", - "enum": [ - "output", - "source_comparison", - "expectation" - ], - "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + "$ref": "#/components/schemas/KeylessFeedbackBasis" }, "comparison": { - "type": "object", - "properties": { - "reference": { - "type": "string", - "minLength": 1, - "maxLength": 2048 - }, - "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 - } - }, - "required": [ - "reference", - "detail" - ], - "additionalProperties": false + "$ref": "#/components/schemas/KeylessFeedbackComparison" }, "format": { "type": "string", @@ -12756,38 +12544,13 @@ "type": "object", "properties": { "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 + "$ref": "#/components/schemas/KeylessFeedbackDetail" }, "basis": { - "type": "string", - "enum": [ - "output", - "source_comparison", - "expectation" - ], - "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + "$ref": "#/components/schemas/KeylessFeedbackBasis" }, "comparison": { - "type": "object", - "properties": { - "reference": { - "type": "string", - "minLength": 1, - "maxLength": 2048 - }, - "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 - } - }, - "required": [ - "reference", - "detail" - ], - "additionalProperties": false + "$ref": "#/components/schemas/KeylessFeedbackComparison" }, "format": { "type": "string", @@ -12844,38 +12607,13 @@ "type": "object", "properties": { "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 + "$ref": "#/components/schemas/KeylessFeedbackDetail" }, "basis": { - "type": "string", - "enum": [ - "output", - "source_comparison", - "expectation" - ], - "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + "$ref": "#/components/schemas/KeylessFeedbackBasis" }, "comparison": { - "type": "object", - "properties": { - "reference": { - "type": "string", - "minLength": 1, - "maxLength": 2048 - }, - "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 - } - }, - "required": [ - "reference", - "detail" - ], - "additionalProperties": false + "$ref": "#/components/schemas/KeylessFeedbackComparison" }, "format": { "type": "string", @@ -12932,38 +12670,13 @@ "type": "object", "properties": { "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 + "$ref": "#/components/schemas/KeylessFeedbackDetail" }, "basis": { - "type": "string", - "enum": [ - "output", - "source_comparison", - "expectation" - ], - "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + "$ref": "#/components/schemas/KeylessFeedbackBasis" }, "comparison": { - "type": "object", - "properties": { - "reference": { - "type": "string", - "minLength": 1, - "maxLength": 2048 - }, - "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 - } - }, - "required": [ - "reference", - "detail" - ], - "additionalProperties": false + "$ref": "#/components/schemas/KeylessFeedbackComparison" }, "format": { "type": "string", @@ -13020,38 +12733,13 @@ "type": "object", "properties": { "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 + "$ref": "#/components/schemas/KeylessFeedbackDetail" }, "basis": { - "type": "string", - "enum": [ - "output", - "source_comparison", - "expectation" - ], - "description": "Use source_comparison only when you already inspected the source; include comparison.reference and comparison.detail. Use expectation for an unmet need not verified against the source." + "$ref": "#/components/schemas/KeylessFeedbackBasis" }, "comparison": { - "type": "object", - "properties": { - "reference": { - "type": "string", - "minLength": 1, - "maxLength": 2048 - }, - "detail": { - "type": "string", - "minLength": 10, - "maxLength": 2000 - } - }, - "required": [ - "reference", - "detail" - ], - "additionalProperties": false + "$ref": "#/components/schemas/KeylessFeedbackComparison" }, "format": { "type": "string", @@ -13120,8 +12808,40 @@ "additionalProperties": false, "title": "Parse" } + ] + }, + "KeylessFeedbackDetail": { + "type": "string", + "minLength": 10, + "maxLength": 2000, + "description": "Length is measured after trimming whitespace." + }, + "KeylessFeedbackBasis": { + "type": "string", + "enum": [ + "output", + "source_comparison", + "expectation" + ], + "description": "Use output for returned content, source_comparison with comparison for a source you already inspected, or expectation for an unmet need." + }, + "KeylessFeedbackComparison": { + "type": "object", + "properties": { + "reference": { + "type": "string", + "minLength": 1, + "maxLength": 2048 + }, + "detail": { + "$ref": "#/components/schemas/KeylessFeedbackDetail" + } + }, + "required": [ + "reference", + "detail" ], - "description": "Optional evidence for a keyless Search, Scrape, or Parse job. Text length limits apply after trimming leading and trailing whitespace. Use observations already available from the task; distinguish returned output, source comparisons, and unmet expectations." + "additionalProperties": false } } }, From 12911ad02adb955bee360c931051a6909813ea11 Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Sun, 13 Sep 2026 21:15:54 -0500 Subject: [PATCH 11/25] docs: rebuild keyless feedback reference using existing conventions --- api-reference/endpoint/feedback.mdx | 44 +- api-reference/endpoint/parse.mdx | 4 +- api-reference/endpoint/scrape.mdx | 4 +- api-reference/endpoint/search.mdx | 4 +- api-reference/v2-openapi.json | 979 ++++++++++++++-------------- 5 files changed, 518 insertions(+), 517 deletions(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index 44dded8c1..2e08066d2 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -1,14 +1,28 @@ --- title: 'Feedback' -description: 'Share feedback on a Firecrawl job.' +description: 'Submit feedback for a Firecrawl job.' openapi: '/api-reference/v2-openapi.json POST /feedback' --- -Share what worked and what needs improvement. +Submit feedback on the quality of a job's output, including useful results, missing content, or incorrect data. -For keyless Search, Scrape, or Parse jobs, omit `Authorization` and select the matching request format below. Use the job ID returned by the operation. One submission is accepted per keyless identity per UTC day, shared across endpoints and clients. +For jobs created with an API key, include your key and use the Authenticated request format. For keyless Search, Scrape, or Parse jobs, omit `Authorization` and use the matching request format. Keyless feedback is optional and limited to one accepted submission per identity per UTC day across all three endpoints and clients. -For jobs created with an API key, include your key and select Authenticated below. [Search Feedback](/api-reference/endpoint/search-feedback) remains the preferred entry point for authenticated Search jobs. +### Example request + +```bash +curl -X POST "https://api.firecrawl.dev/v2/feedback" \ + -H "Authorization: Bearer $FIRECRAWL_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "endpoint": "scrape", + "jobId": "550e8400-e29b-41d4-a716-446655440000", + "rating": "partial", + "issues": ["missing_markdown"], + "note": "The pricing table was missing from the markdown output.", + "url": "https://example.com/pricing" + }' +``` ### Keyless example @@ -17,7 +31,7 @@ curl -X POST "https://api.firecrawl.dev/v2/feedback" \ -H "Content-Type: application/json" \ -d '{ "endpoint": "search", - "jobId": "00000000-0000-4000-8000-000000000001", + "jobId": "550e8400-e29b-41d4-a716-446655440000", "rating": "good", "task": "Find the documented retry behavior", "assessment": "The API reference answered the retry question.", @@ -26,25 +40,9 @@ curl -X POST "https://api.firecrawl.dev/v2/feedback" \ "kind": "useful", "source": "web", "position": 1, - "basis": "output", - "detail": "The reference specifies the retry intervals." + "detail": "The reference specifies the retry intervals.", + "basis": "output" } ] }' ``` - -### Authenticated example - -```bash -curl -X POST "https://api.firecrawl.dev/v2/feedback" \ - -H "Authorization: Bearer $FIRECRAWL_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "endpoint": "scrape", - "jobId": "550e8400-e29b-41d4-a716-446655440000", - "rating": "partial", - "issues": ["missing_markdown"], - "note": "The pricing table was missing from the markdown output.", - "url": "https://example.com/pricing" - }' -``` diff --git a/api-reference/endpoint/parse.mdx b/api-reference/endpoint/parse.mdx index 91e085482..82d40cabe 100644 --- a/api-reference/endpoint/parse.mdx +++ b/api-reference/endpoint/parse.mdx @@ -23,6 +23,4 @@ Use `/parse` when the source document is **a local file** or **not publicly acce **Using Firecrawl through MCP?** Use `firecrawl_parse` for local files. Local MCP can read the file directly when configured with `FIRECRAWL_API_URL`. Remote hosted MCP returns a short-lived upload command first, then parses the returned `uploadRef`. Public document URLs should still use `/scrape`. -## Optional keyless feedback - -Eligible keyless responses may include an invitation to submit [feedback](/api-reference/endpoint/feedback). Use the returned `jobId` and observations already available from your task. Submitting feedback is optional. +Keyless responses may include an invitation to submit [feedback](/api-reference/endpoint/feedback) about the result. diff --git a/api-reference/endpoint/scrape.mdx b/api-reference/endpoint/scrape.mdx index 40d8cf75c..9335960fe 100644 --- a/api-reference/endpoint/scrape.mdx +++ b/api-reference/endpoint/scrape.mdx @@ -17,6 +17,4 @@ Optionally you can also use the `actions` parameter, although it's not recommend > Are you an AI agent that needs a Firecrawl API key? See [firecrawl.dev/agent-onboarding/SKILL.md](https://www.firecrawl.dev/agent-onboarding/SKILL.md) for automated onboarding instructions. -## Optional keyless feedback - -Eligible keyless responses may include an invitation to submit [feedback](/api-reference/endpoint/feedback). Use the returned `jobId` and observations already available from your task. Submitting feedback is optional. +Keyless responses may include an invitation to submit [feedback](/api-reference/endpoint/feedback) about the result. diff --git a/api-reference/endpoint/search.mdx b/api-reference/endpoint/search.mdx index 09ca4c452..aa7b871b0 100644 --- a/api-reference/endpoint/search.mdx +++ b/api-reference/endpoint/search.mdx @@ -125,6 +125,4 @@ Use the `tbs` parameter to filter results by time periods, including custom date > Are you an AI agent that needs a Firecrawl API key? See [firecrawl.dev/agent-onboarding/SKILL.md](https://www.firecrawl.dev/agent-onboarding/SKILL.md) for automated onboarding instructions. -## Optional keyless feedback - -Eligible keyless responses may include an invitation to submit [feedback](/api-reference/endpoint/feedback). Use the returned `id` and observations already available from your task. Submitting feedback is optional. +Keyless responses may include an invitation to submit [feedback](/api-reference/endpoint/feedback) about the result. diff --git a/api-reference/v2-openapi.json b/api-reference/v2-openapi.json index 3ec32966c..50b017c5c 100644 --- a/api-reference/v2-openapi.json +++ b/api-reference/v2-openapi.json @@ -566,8 +566,7 @@ } } } - }, - "description": "Eligible keyless responses may include an optional feedback invitation in data.metadata. Submit feedback for this job through POST /v2/feedback using the returned jobId." + } } }, "/scrape/{jobId}/interact": { @@ -1076,8 +1075,7 @@ } } } - }, - "description": "Eligible keyless responses may include an optional feedback invitation in data.metadata. Submit feedback for this job through POST /v2/feedback using the returned jobId." + } } }, "/batch/scrape": { @@ -4510,8 +4508,7 @@ } } } - }, - "description": "Eligible keyless responses may include an optional feedback invitation in top-level metadata. Submit feedback for this job through POST /v2/feedback using the returned id." + } } }, "/interact": { @@ -6011,7 +6008,7 @@ "security": [ {}, { - "feedbackBearerAuth": [] + "bearerAuth": [] } ], "requestBody": { @@ -6020,9 +6017,6 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/KeylessFeedbackRequest" - }, { "title": "Authenticated", "allOf": [ @@ -6030,6 +6024,9 @@ "$ref": "#/components/schemas/EndpointFeedbackRequest" } ] + }, + { + "$ref": "#/components/schemas/KeylessFeedbackRequest" } ] } @@ -6068,7 +6065,7 @@ } }, "404": { - "description": "No eligible job found for this caller and endpoint", + "description": "Job not found for this caller", "content": { "application/json": { "schema": { @@ -6097,8 +6094,8 @@ } } }, - "429": { - "description": "Too many feedback requests", + "401": { + "description": "Authentication failed or keyless access is unavailable", "content": { "application/json": { "schema": { @@ -6107,8 +6104,8 @@ } } }, - "503": { - "description": "Feedback is temporarily unavailable", + "429": { + "description": "Too many feedback requests", "content": { "application/json": { "schema": { @@ -6117,8 +6114,8 @@ } } }, - "401": { - "description": "Authentication failed or keyless access is unavailable", + "503": { + "description": "Feedback is temporarily unavailable", "content": { "application/json": { "schema": { @@ -6128,7 +6125,7 @@ } } }, - "description": "Submit optional feedback for a job. Keyless requests support Search, Scrape, and Parse. Authenticated requests also support Map." + "description": "Submit feedback for a job. Keyless feedback supports Search, Scrape, and Parse. One accepted submission per keyless identity per UTC day, shared across these endpoints and clients." } }, "/team/threat-protection": { @@ -6434,11 +6431,6 @@ "bearerAuth": { "type": "http", "scheme": "bearer" - }, - "feedbackBearerAuth": { - "type": "http", - "scheme": "bearer", - "description": "For authenticated jobs, send `Bearer `. Omit this header for keyless jobs." } }, "parameters": { @@ -11821,16 +11813,58 @@ } } }, + "FeedbackComparison": { + "type": "object", + "properties": { + "reference": { + "type": "string", + "description": "URL or location of the source you compared.", + "minLength": 1, + "maxLength": 2048 + }, + "detail": { + "type": "string", + "description": "How the source differs from the output.", + "minLength": 10, + "maxLength": 2000 + } + }, + "required": [ + "reference", + "detail" + ], + "additionalProperties": false + }, + "FeedbackDetail": { + "type": "string", + "description": "Describe what you observed.", + "minLength": 10, + "maxLength": 2000 + }, + "FeedbackBasis": { + "type": "string", + "enum": [ + "output", + "source_comparison", + "expectation" + ], + "description": "What supports the observation. Use source_comparison only with a source you already inspected; include comparison. Use expectation for an unmet need." + }, "KeylessFeedbackRequest": { "anyOf": [ { "type": "object", "properties": { + "endpoint": { + "type": "string", + "enum": [ + "search" + ] + }, "jobId": { "type": "string", "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", - "description": "Job reference returned for the same caller and endpoint." + "description": "Job ID returned by /search." }, "rating": { "type": "string", @@ -11838,47 +11872,36 @@ "good", "partial", "bad" - ] + ], + "description": "Overall quality of the result." }, "task": { - "$ref": "#/components/schemas/KeylessFeedbackDetail" - }, - "assessment": { - "$ref": "#/components/schemas/KeylessFeedbackDetail" - }, - "origin": { - "default": "api", - "type": "string", - "maxLength": 100 - }, - "integration": { - "nullable": true, "type": "string", - "maxLength": 100 + "description": "What you were trying to accomplish.", + "minLength": 10, + "maxLength": 2000 }, - "endpoint": { + "assessment": { "type": "string", - "enum": [ - "search" - ] + "description": "How well the result met your needs.", + "minLength": 10, + "maxLength": 2000 }, "observations": { + "type": "array", + "description": "Specific results or content you want to give feedback on. Text is trimmed before length validation.", "minItems": 1, "maxItems": 20, - "type": "array", "items": { "anyOf": [ { "type": "object", "properties": { - "detail": { - "$ref": "#/components/schemas/KeylessFeedbackDetail" - }, - "basis": { - "$ref": "#/components/schemas/KeylessFeedbackBasis" - }, - "comparison": { - "$ref": "#/components/schemas/KeylessFeedbackComparison" + "kind": { + "type": "string", + "enum": [ + "useful" + ] }, "source": { "type": "string", @@ -11887,13 +11910,13 @@ "images", "news" ], - "description": "Response group the position refers to. Required when the job requested multiple sources; otherwise defaults to web. The source and position must exist in the requested, delivered results." + "description": "Result group containing the position. Required when the search requested multiple sources; otherwise defaults to web." }, "position": { "type": "integer", - "maximum": 9007199254740991, - "description": "One-based position within the delivered response group.", - "minimum": 1 + "minimum": 1, + "description": "Position in the returned result group, starting at 1.", + "example": 1 }, "vertical": { "type": "string", @@ -11907,52 +11930,50 @@ "government", "finance", "other" - ] + ], + "description": "Subject area you were looking for." }, - "kind": { - "type": "string", - "enum": [ - "useful" - ] + "detail": { + "$ref": "#/components/schemas/FeedbackDetail" + }, + "basis": { + "$ref": "#/components/schemas/FeedbackBasis" + }, + "comparison": { + "$ref": "#/components/schemas/FeedbackComparison" } }, "required": [ + "kind", "detail", "basis", - "position", - "kind" + "position" ], "additionalProperties": false, "title": "useful", - "anyOf": [ - { - "properties": { - "basis": { - "enum": [ - "output", - "expectation" - ] - } + "not": { + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] } }, - { + "not": { "required": [ "comparison" ] } - ] + } }, { "type": "object", "properties": { - "detail": { - "$ref": "#/components/schemas/KeylessFeedbackDetail" - }, - "basis": { - "$ref": "#/components/schemas/KeylessFeedbackBasis" - }, - "comparison": { - "$ref": "#/components/schemas/KeylessFeedbackComparison" + "kind": { + "type": "string", + "enum": [ + "irrelevant" + ] }, "source": { "type": "string", @@ -11961,13 +11982,13 @@ "images", "news" ], - "description": "Response group the position refers to. Required when the job requested multiple sources; otherwise defaults to web. The source and position must exist in the requested, delivered results." + "description": "Result group containing the position. Required when the search requested multiple sources; otherwise defaults to web." }, "position": { "type": "integer", - "maximum": 9007199254740991, - "description": "One-based position within the delivered response group.", - "minimum": 1 + "minimum": 1, + "description": "Position in the returned result group, starting at 1.", + "example": 1 }, "vertical": { "type": "string", @@ -11981,13 +12002,8 @@ "government", "finance", "other" - ] - }, - "kind": { - "type": "string", - "enum": [ - "irrelevant" - ] + ], + "description": "Subject area you were looking for." }, "reason": { "type": "string", @@ -11998,48 +12014,46 @@ "wrong_content_type", "snippet_misleading", "blocked_or_paywalled" - ] + ], + "description": "Reason for the issue." + }, + "detail": { + "$ref": "#/components/schemas/FeedbackDetail" + }, + "basis": { + "$ref": "#/components/schemas/FeedbackBasis" + }, + "comparison": { + "$ref": "#/components/schemas/FeedbackComparison" } }, "required": [ + "kind", "detail", "basis", "position", - "kind", "reason" ], "additionalProperties": false, "title": "irrelevant", - "anyOf": [ - { - "properties": { - "basis": { - "enum": [ - "output", - "expectation" - ] - } + "not": { + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] } }, - { + "not": { "required": [ "comparison" ] } - ] + } }, { "type": "object", "properties": { - "detail": { - "$ref": "#/components/schemas/KeylessFeedbackDetail" - }, - "basis": { - "$ref": "#/components/schemas/KeylessFeedbackBasis" - }, - "comparison": { - "$ref": "#/components/schemas/KeylessFeedbackComparison" - }, "kind": { "type": "string", "enum": [ @@ -12058,59 +12072,80 @@ "government", "finance", "other" - ] + ], + "description": "Subject area you were looking for." }, "topic": { "type": "string", + "description": "Information missing from the results.", "minLength": 1, "maxLength": 200 }, "knownSources": { - "maxItems": 20, "type": "array", + "description": "Known sources that were missing from the results.", + "maxItems": 20, "items": { "type": "string", "format": "uri", "pattern": "^https?://" } + }, + "detail": { + "$ref": "#/components/schemas/FeedbackDetail" + }, + "basis": { + "$ref": "#/components/schemas/FeedbackBasis" + }, + "comparison": { + "$ref": "#/components/schemas/FeedbackComparison" } }, "required": [ + "kind", "detail", "basis", - "kind", "vertical" ], "additionalProperties": false, "title": "missing", - "anyOf": [ - { - "properties": { - "basis": { - "enum": [ - "output", - "expectation" - ] - } + "not": { + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] } }, - { + "not": { "required": [ "comparison" ] } - ] + } } ] } + }, + "origin": { + "type": "string", + "description": "Client submitting the feedback.", + "maxLength": 100, + "default": "api" + }, + "integration": { + "type": "string", + "description": "Integration submitting the feedback.", + "maxLength": 100, + "nullable": true } }, "required": [ + "endpoint", "jobId", "rating", "task", "assessment", - "endpoint", "observations" ], "additionalProperties": false, @@ -12119,11 +12154,16 @@ { "type": "object", "properties": { + "endpoint": { + "type": "string", + "enum": [ + "scrape" + ] + }, "jobId": { "type": "string", "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", - "description": "Job reference returned for the same caller and endpoint." + "description": "Job ID returned by /scrape." }, "rating": { "type": "string", @@ -12131,118 +12171,100 @@ "good", "partial", "bad" - ] + ], + "description": "Overall quality of the result." }, "task": { - "$ref": "#/components/schemas/KeylessFeedbackDetail" - }, - "assessment": { - "$ref": "#/components/schemas/KeylessFeedbackDetail" - }, - "origin": { - "default": "api", - "type": "string", - "maxLength": 100 - }, - "integration": { - "nullable": true, "type": "string", - "maxLength": 100 + "description": "What you were trying to accomplish.", + "minLength": 10, + "maxLength": 2000 }, - "endpoint": { + "assessment": { "type": "string", - "enum": [ - "scrape" - ] + "description": "How well the result met your needs.", + "minLength": 10, + "maxLength": 2000 }, "observations": { + "type": "array", + "description": "Specific results or content you want to give feedback on. Text is trimmed before length validation.", "minItems": 1, "maxItems": 20, - "type": "array", "items": { "anyOf": [ { "type": "object", "properties": { - "detail": { - "$ref": "#/components/schemas/KeylessFeedbackDetail" - }, - "basis": { - "$ref": "#/components/schemas/KeylessFeedbackBasis" - }, - "comparison": { - "$ref": "#/components/schemas/KeylessFeedbackComparison" + "kind": { + "type": "string", + "enum": [ + "correct" + ] }, "format": { "type": "string", - "minLength": 1, - "description": "A format type requested by the job. Required for output and source_comparison observations when multiple formats were requested; optional otherwise." + "description": "Output format requested by the job. Required when multiple formats were requested, except for expectation observations.", + "minLength": 1 }, "location": { "type": "string", + "description": "Location of the content in the page or output.", "minLength": 1, "maxLength": 200 }, - "kind": { - "type": "string", - "enum": [ - "correct" - ] + "detail": { + "$ref": "#/components/schemas/FeedbackDetail" + }, + "basis": { + "$ref": "#/components/schemas/FeedbackBasis" + }, + "comparison": { + "$ref": "#/components/schemas/FeedbackComparison" } }, "required": [ + "kind", "detail", - "basis", - "kind" + "basis" ], "additionalProperties": false, "title": "correct", - "anyOf": [ - { - "properties": { - "basis": { - "enum": [ - "output", - "expectation" - ] - } + "not": { + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] } }, - { + "not": { "required": [ "comparison" ] } - ] + } }, { "type": "object", "properties": { - "detail": { - "$ref": "#/components/schemas/KeylessFeedbackDetail" - }, - "basis": { - "$ref": "#/components/schemas/KeylessFeedbackBasis" - }, - "comparison": { - "$ref": "#/components/schemas/KeylessFeedbackComparison" - }, - "format": { + "kind": { "type": "string", - "minLength": 1, - "description": "A format type requested by the job. Required for output and source_comparison observations when multiple formats were requested; optional otherwise." + "enum": [ + "wrong_success" + ] + }, + "format": { + "type": "string", + "description": "Output format requested by the job. Required when multiple formats were requested, except for expectation observations.", + "minLength": 1 }, "location": { "type": "string", + "description": "Location of the content in the page or output.", "minLength": 1, "maxLength": 200 }, - "kind": { - "type": "string", - "enum": [ - "wrong_success" - ] - }, "reason": { "type": "string", "enum": [ @@ -12253,63 +12275,62 @@ "wrong_page", "stale", "wrong_locale" - ] + ], + "description": "Reason for the issue." + }, + "detail": { + "$ref": "#/components/schemas/FeedbackDetail" + }, + "basis": { + "$ref": "#/components/schemas/FeedbackBasis" + }, + "comparison": { + "$ref": "#/components/schemas/FeedbackComparison" } }, "required": [ + "kind", "detail", "basis", - "kind", "reason" ], "additionalProperties": false, "title": "wrong_success", - "anyOf": [ - { - "properties": { - "basis": { - "enum": [ - "output", - "expectation" - ] - } + "not": { + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] } }, - { + "not": { "required": [ "comparison" ] } - ] + } }, { "type": "object", "properties": { - "detail": { - "$ref": "#/components/schemas/KeylessFeedbackDetail" - }, - "basis": { - "$ref": "#/components/schemas/KeylessFeedbackBasis" - }, - "comparison": { - "$ref": "#/components/schemas/KeylessFeedbackComparison" + "kind": { + "type": "string", + "enum": [ + "incomplete" + ] }, "format": { "type": "string", - "minLength": 1, - "description": "A format type requested by the job. Required for output and source_comparison observations when multiple formats were requested; optional otherwise." + "description": "Output format requested by the job. Required when multiple formats were requested, except for expectation observations.", + "minLength": 1 }, "location": { "type": "string", + "description": "Location of the content in the page or output.", "minLength": 1, "maxLength": 200 }, - "kind": { - "type": "string", - "enum": [ - "incomplete" - ] - }, "reason": { "type": "string", "enum": [ @@ -12318,108 +12339,126 @@ "pagination", "main_content_stripped", "format_lost" - ] + ], + "description": "Reason for the issue." + }, + "detail": { + "$ref": "#/components/schemas/FeedbackDetail" + }, + "basis": { + "$ref": "#/components/schemas/FeedbackBasis" + }, + "comparison": { + "$ref": "#/components/schemas/FeedbackComparison" } }, "required": [ + "kind", "detail", "basis", - "kind", "reason" ], "additionalProperties": false, "title": "incomplete", - "anyOf": [ - { - "properties": { - "basis": { - "enum": [ - "output", - "expectation" - ] - } + "not": { + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] } }, - { + "not": { "required": [ "comparison" ] } - ] + } }, { "type": "object", "properties": { - "detail": { - "$ref": "#/components/schemas/KeylessFeedbackDetail" - }, - "basis": { - "$ref": "#/components/schemas/KeylessFeedbackBasis" - }, - "comparison": { - "$ref": "#/components/schemas/KeylessFeedbackComparison" + "kind": { + "type": "string", + "enum": [ + "incorrect" + ] }, "format": { "type": "string", - "minLength": 1, - "description": "A format type requested by the job. Required for output and source_comparison observations when multiple formats were requested; optional otherwise." + "description": "Output format requested by the job. Required when multiple formats were requested, except for expectation observations.", + "minLength": 1 }, "location": { "type": "string", + "description": "Location of the content in the page or output.", "minLength": 1, "maxLength": 200 }, - "kind": { - "type": "string", - "enum": [ - "incorrect" - ] - }, "reason": { "type": "string", "enum": [ "wrong", "hallucinated", "missing_fields" - ] + ], + "description": "Reason for the issue." + }, + "detail": { + "$ref": "#/components/schemas/FeedbackDetail" + }, + "basis": { + "$ref": "#/components/schemas/FeedbackBasis" + }, + "comparison": { + "$ref": "#/components/schemas/FeedbackComparison" } }, "required": [ + "kind", "detail", "basis", - "kind", "reason" ], "additionalProperties": false, "title": "incorrect", - "anyOf": [ - { - "properties": { - "basis": { - "enum": [ - "output", - "expectation" - ] - } + "not": { + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] } }, - { + "not": { "required": [ "comparison" ] } - ] + } } ] } + }, + "origin": { + "type": "string", + "description": "Client submitting the feedback.", + "maxLength": 100, + "default": "api" + }, + "integration": { + "type": "string", + "description": "Integration submitting the feedback.", + "maxLength": 100, + "nullable": true } }, "required": [ + "endpoint", "jobId", "rating", "task", "assessment", - "endpoint", "observations" ], "additionalProperties": false, @@ -12428,11 +12467,16 @@ { "type": "object", "properties": { + "endpoint": { + "type": "string", + "enum": [ + "parse" + ] + }, "jobId": { "type": "string", "format": "uuid", - "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$", - "description": "Job reference returned for the same caller and endpoint." + "description": "Job ID returned by /parse." }, "rating": { "type": "string", @@ -12440,29 +12484,20 @@ "good", "partial", "bad" - ] + ], + "description": "Overall quality of the result." }, "task": { - "$ref": "#/components/schemas/KeylessFeedbackDetail" - }, - "assessment": { - "$ref": "#/components/schemas/KeylessFeedbackDetail" - }, - "origin": { - "default": "api", - "type": "string", - "maxLength": 100 - }, - "integration": { - "nullable": true, "type": "string", - "maxLength": 100 + "description": "What you were trying to accomplish.", + "minLength": 10, + "maxLength": 2000 }, - "endpoint": { + "assessment": { "type": "string", - "enum": [ - "parse" - ] + "description": "How well the result met your needs.", + "minLength": 10, + "maxLength": 2000 }, "docClass": { "type": "string", @@ -12472,36 +12507,18 @@ "mixed", "unknown" ], - "description": "Document class, provided once for the submission. Use unknown when the class is not already known." + "description": "Type of document. Use unknown if you cannot determine the type." }, "observations": { + "type": "array", + "description": "Specific results or content you want to give feedback on. Text is trimmed before length validation.", "minItems": 1, "maxItems": 20, - "type": "array", "items": { "anyOf": [ { "type": "object", "properties": { - "detail": { - "$ref": "#/components/schemas/KeylessFeedbackDetail" - }, - "basis": { - "$ref": "#/components/schemas/KeylessFeedbackBasis" - }, - "comparison": { - "$ref": "#/components/schemas/KeylessFeedbackComparison" - }, - "format": { - "type": "string", - "minLength": 1, - "description": "A format type requested by the job. Required for output and source_comparison observations when multiple formats were requested; optional otherwise." - }, - "page": { - "type": "integer", - "maximum": 9007199254740991, - "minimum": 1 - }, "kind": { "type": "string", "enum": [ @@ -12513,60 +12530,69 @@ "headings_formatting", "images_dropped" ] + }, + "format": { + "type": "string", + "description": "Output format requested by the job. Required when multiple formats were requested, except for expectation observations.", + "minLength": 1 + }, + "page": { + "type": "integer", + "minimum": 1, + "description": "Page number, starting at 1.", + "example": 1 + }, + "detail": { + "$ref": "#/components/schemas/FeedbackDetail" + }, + "basis": { + "$ref": "#/components/schemas/FeedbackBasis" + }, + "comparison": { + "$ref": "#/components/schemas/FeedbackComparison" } }, "required": [ + "kind", "detail", - "basis", - "kind" + "basis" ], "additionalProperties": false, - "title": "correct / formula / chart_figure / reading_order / headers_footers / headings_formatting / images_dropped", - "anyOf": [ - { - "properties": { - "basis": { - "enum": [ - "output", - "expectation" - ] - } + "title": "Other", + "not": { + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] } }, - { + "not": { "required": [ "comparison" ] } - ] + } }, { "type": "object", "properties": { - "detail": { - "$ref": "#/components/schemas/KeylessFeedbackDetail" - }, - "basis": { - "$ref": "#/components/schemas/KeylessFeedbackBasis" - }, - "comparison": { - "$ref": "#/components/schemas/KeylessFeedbackComparison" + "kind": { + "type": "string", + "enum": [ + "text_ocr" + ] }, "format": { "type": "string", - "minLength": 1, - "description": "A format type requested by the job. Required for output and source_comparison observations when multiple formats were requested; optional otherwise." + "description": "Output format requested by the job. Required when multiple formats were requested, except for expectation observations.", + "minLength": 1 }, "page": { "type": "integer", - "maximum": 9007199254740991, - "minimum": 1 - }, - "kind": { - "type": "string", - "enum": [ - "text_ocr" - ] + "minimum": 1, + "description": "Page number, starting at 1.", + "example": 1 }, "reason": { "type": "string", @@ -12574,62 +12600,61 @@ "misread_chars", "garbled", "missing_text" - ] + ], + "description": "Reason for the issue." + }, + "detail": { + "$ref": "#/components/schemas/FeedbackDetail" + }, + "basis": { + "$ref": "#/components/schemas/FeedbackBasis" + }, + "comparison": { + "$ref": "#/components/schemas/FeedbackComparison" } }, "required": [ + "kind", "detail", "basis", - "kind", "reason" ], "additionalProperties": false, "title": "text_ocr", - "anyOf": [ - { - "properties": { - "basis": { - "enum": [ - "output", - "expectation" - ] - } + "not": { + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] } }, - { + "not": { "required": [ "comparison" ] } - ] + } }, { "type": "object", "properties": { - "detail": { - "$ref": "#/components/schemas/KeylessFeedbackDetail" - }, - "basis": { - "$ref": "#/components/schemas/KeylessFeedbackBasis" - }, - "comparison": { - "$ref": "#/components/schemas/KeylessFeedbackComparison" + "kind": { + "type": "string", + "enum": [ + "table" + ] }, "format": { "type": "string", - "minLength": 1, - "description": "A format type requested by the job. Required for output and source_comparison observations when multiple formats were requested; optional otherwise." + "description": "Output format requested by the job. Required when multiple formats were requested, except for expectation observations.", + "minLength": 1 }, "page": { "type": "integer", - "maximum": 9007199254740991, - "minimum": 1 - }, - "kind": { - "type": "string", - "enum": [ - "table" - ] + "minimum": 1, + "description": "Page number, starting at 1.", + "example": 1 }, "reason": { "type": "string", @@ -12637,62 +12662,61 @@ "structure", "cells_glued", "digits" - ] + ], + "description": "Reason for the issue." + }, + "detail": { + "$ref": "#/components/schemas/FeedbackDetail" + }, + "basis": { + "$ref": "#/components/schemas/FeedbackBasis" + }, + "comparison": { + "$ref": "#/components/schemas/FeedbackComparison" } }, "required": [ + "kind", "detail", "basis", - "kind", "reason" ], "additionalProperties": false, "title": "table", - "anyOf": [ - { - "properties": { - "basis": { - "enum": [ - "output", - "expectation" - ] - } + "not": { + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] } }, - { + "not": { "required": [ "comparison" ] } - ] + } }, { "type": "object", "properties": { - "detail": { - "$ref": "#/components/schemas/KeylessFeedbackDetail" - }, - "basis": { - "$ref": "#/components/schemas/KeylessFeedbackBasis" - }, - "comparison": { - "$ref": "#/components/schemas/KeylessFeedbackComparison" + "kind": { + "type": "string", + "enum": [ + "completeness" + ] }, "format": { "type": "string", - "minLength": 1, - "description": "A format type requested by the job. Required for output and source_comparison observations when multiple formats were requested; optional otherwise." + "description": "Output format requested by the job. Required when multiple formats were requested, except for expectation observations.", + "minLength": 1 }, "page": { "type": "integer", - "maximum": 9007199254740991, - "minimum": 1 - }, - "kind": { - "type": "string", - "enum": [ - "completeness" - ] + "minimum": 1, + "description": "Page number, starting at 1.", + "example": 1 }, "reason": { "type": "string", @@ -12700,62 +12724,61 @@ "pages_missing", "truncated_at_max_pages", "sections_dropped" - ] + ], + "description": "Reason for the issue." + }, + "detail": { + "$ref": "#/components/schemas/FeedbackDetail" + }, + "basis": { + "$ref": "#/components/schemas/FeedbackBasis" + }, + "comparison": { + "$ref": "#/components/schemas/FeedbackComparison" } }, "required": [ + "kind", "detail", "basis", - "kind", "reason" ], "additionalProperties": false, "title": "completeness", - "anyOf": [ - { - "properties": { - "basis": { - "enum": [ - "output", - "expectation" - ] - } + "not": { + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] } }, - { + "not": { "required": [ "comparison" ] } - ] + } }, { "type": "object", "properties": { - "detail": { - "$ref": "#/components/schemas/KeylessFeedbackDetail" - }, - "basis": { - "$ref": "#/components/schemas/KeylessFeedbackBasis" - }, - "comparison": { - "$ref": "#/components/schemas/KeylessFeedbackComparison" + "kind": { + "type": "string", + "enum": [ + "incorrect" + ] }, "format": { "type": "string", - "minLength": 1, - "description": "A format type requested by the job. Required for output and source_comparison observations when multiple formats were requested; optional otherwise." + "description": "Output format requested by the job. Required when multiple formats were requested, except for expectation observations.", + "minLength": 1 }, "page": { "type": "integer", - "maximum": 9007199254740991, - "minimum": 1 - }, - "kind": { - "type": "string", - "enum": [ - "incorrect" - ] + "minimum": 1, + "description": "Page number, starting at 1.", + "example": 1 }, "reason": { "type": "string", @@ -12763,85 +12786,71 @@ "wrong", "hallucinated", "missing_fields" - ] + ], + "description": "Reason for the issue." + }, + "detail": { + "$ref": "#/components/schemas/FeedbackDetail" + }, + "basis": { + "$ref": "#/components/schemas/FeedbackBasis" + }, + "comparison": { + "$ref": "#/components/schemas/FeedbackComparison" } }, "required": [ + "kind", "detail", "basis", - "kind", "reason" ], "additionalProperties": false, "title": "incorrect", - "anyOf": [ - { - "properties": { - "basis": { - "enum": [ - "output", - "expectation" - ] - } + "not": { + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] } }, - { + "not": { "required": [ "comparison" ] } - ] + } } ] } + }, + "origin": { + "type": "string", + "description": "Client submitting the feedback.", + "maxLength": 100, + "default": "api" + }, + "integration": { + "type": "string", + "description": "Integration submitting the feedback.", + "maxLength": 100, + "nullable": true } }, "required": [ + "endpoint", "jobId", "rating", "task", "assessment", - "endpoint", - "docClass", - "observations" + "observations", + "docClass" ], "additionalProperties": false, "title": "Parse" } ] - }, - "KeylessFeedbackDetail": { - "type": "string", - "minLength": 10, - "maxLength": 2000, - "description": "Length is measured after trimming whitespace." - }, - "KeylessFeedbackBasis": { - "type": "string", - "enum": [ - "output", - "source_comparison", - "expectation" - ], - "description": "Use output for returned content, source_comparison with comparison for a source you already inspected, or expectation for an unmet need." - }, - "KeylessFeedbackComparison": { - "type": "object", - "properties": { - "reference": { - "type": "string", - "minLength": 1, - "maxLength": 2048 - }, - "detail": { - "$ref": "#/components/schemas/KeylessFeedbackDetail" - } - }, - "required": [ - "reference", - "detail" - ], - "additionalProperties": false } } }, From b21ff9590972bc5818f43653394868bdb37063eb Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Sun, 13 Sep 2026 21:18:44 -0500 Subject: [PATCH 12/25] docs: simplify keyless feedback limit wording --- api-reference/endpoint/feedback.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index 2e08066d2..23a1533ba 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -6,7 +6,7 @@ openapi: '/api-reference/v2-openapi.json POST /feedback' Submit feedback on the quality of a job's output, including useful results, missing content, or incorrect data. -For jobs created with an API key, include your key and use the Authenticated request format. For keyless Search, Scrape, or Parse jobs, omit `Authorization` and use the matching request format. Keyless feedback is optional and limited to one accepted submission per identity per UTC day across all three endpoints and clients. +For jobs created with an API key, include your key and use the Authenticated request format. For keyless Search, Scrape, or Parse jobs, omit `Authorization` and use the matching request format. Keyless feedback is limited to one accepted submission per identity per UTC day across all three endpoints and clients. ### Example request From f709612d7ea779fd4ee286eb645ce33814f5fceb Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Sun, 13 Sep 2026 21:26:02 -0500 Subject: [PATCH 13/25] docs: clarify feedback instructions and field descriptions --- api-reference/endpoint/feedback.mdx | 6 ++++-- api-reference/v2-openapi.json | 32 ++++++++++++++--------------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index 23a1533ba..58940b4c0 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -6,9 +6,11 @@ openapi: '/api-reference/v2-openapi.json POST /feedback' Submit feedback on the quality of a job's output, including useful results, missing content, or incorrect data. -For jobs created with an API key, include your key and use the Authenticated request format. For keyless Search, Scrape, or Parse jobs, omit `Authorization` and use the matching request format. Keyless feedback is limited to one accepted submission per identity per UTC day across all three endpoints and clients. +For jobs created with an API key, include your key and use the Authenticated request format. For keyless jobs, omit `Authorization` and use the Search, Scrape, or Parse request format. -### Example request +Keyless feedback is limited to one accepted submission per identity per UTC day across all three endpoints and clients. + +### Authenticated example ```bash curl -X POST "https://api.firecrawl.dev/v2/feedback" \ diff --git a/api-reference/v2-openapi.json b/api-reference/v2-openapi.json index 50b017c5c..d964cde91 100644 --- a/api-reference/v2-openapi.json +++ b/api-reference/v2-openapi.json @@ -11848,7 +11848,7 @@ "source_comparison", "expectation" ], - "description": "What supports the observation. Use source_comparison only with a source you already inspected; include comparison. Use expectation for an unmet need." + "description": "What supports the observation. Use `output` for returned content, `source_comparison` for a source you already inspected, or `expectation` for an unmet need. Include `comparison` when using `source_comparison`." }, "KeylessFeedbackRequest": { "anyOf": [ @@ -11889,7 +11889,7 @@ }, "observations": { "type": "array", - "description": "Specific results or content you want to give feedback on. Text is trimmed before length validation.", + "description": "Specific observations about the result. Text limits exclude leading and trailing whitespace.", "minItems": 1, "maxItems": 20, "items": { @@ -11910,7 +11910,7 @@ "images", "news" ], - "description": "Result group containing the position. Required when the search requested multiple sources; otherwise defaults to web." + "description": "Result group the position refers to. Required when the search requested multiple sources. Defaults to `web` otherwise." }, "position": { "type": "integer", @@ -11982,7 +11982,7 @@ "images", "news" ], - "description": "Result group containing the position. Required when the search requested multiple sources; otherwise defaults to web." + "description": "Result group the position refers to. Required when the search requested multiple sources. Defaults to `web` otherwise." }, "position": { "type": "integer", @@ -12188,7 +12188,7 @@ }, "observations": { "type": "array", - "description": "Specific results or content you want to give feedback on. Text is trimmed before length validation.", + "description": "Specific observations about the result. Text limits exclude leading and trailing whitespace.", "minItems": 1, "maxItems": 20, "items": { @@ -12204,7 +12204,7 @@ }, "format": { "type": "string", - "description": "Output format requested by the job. Required when multiple formats were requested, except for expectation observations.", + "description": "Requested output format this observation refers to. Required when the job requested multiple formats and `basis` is `output` or `source_comparison`.", "minLength": 1 }, "location": { @@ -12256,7 +12256,7 @@ }, "format": { "type": "string", - "description": "Output format requested by the job. Required when multiple formats were requested, except for expectation observations.", + "description": "Requested output format this observation refers to. Required when the job requested multiple formats and `basis` is `output` or `source_comparison`.", "minLength": 1 }, "location": { @@ -12322,7 +12322,7 @@ }, "format": { "type": "string", - "description": "Output format requested by the job. Required when multiple formats were requested, except for expectation observations.", + "description": "Requested output format this observation refers to. Required when the job requested multiple formats and `basis` is `output` or `source_comparison`.", "minLength": 1 }, "location": { @@ -12386,7 +12386,7 @@ }, "format": { "type": "string", - "description": "Output format requested by the job. Required when multiple formats were requested, except for expectation observations.", + "description": "Requested output format this observation refers to. Required when the job requested multiple formats and `basis` is `output` or `source_comparison`.", "minLength": 1 }, "location": { @@ -12507,11 +12507,11 @@ "mixed", "unknown" ], - "description": "Type of document. Use unknown if you cannot determine the type." + "description": "Type of document. Use `unknown` if you cannot determine the type." }, "observations": { "type": "array", - "description": "Specific results or content you want to give feedback on. Text is trimmed before length validation.", + "description": "Specific observations about the result. Text limits exclude leading and trailing whitespace.", "minItems": 1, "maxItems": 20, "items": { @@ -12533,7 +12533,7 @@ }, "format": { "type": "string", - "description": "Output format requested by the job. Required when multiple formats were requested, except for expectation observations.", + "description": "Requested output format this observation refers to. Required when the job requested multiple formats and `basis` is `output` or `source_comparison`.", "minLength": 1 }, "page": { @@ -12585,7 +12585,7 @@ }, "format": { "type": "string", - "description": "Output format requested by the job. Required when multiple formats were requested, except for expectation observations.", + "description": "Requested output format this observation refers to. Required when the job requested multiple formats and `basis` is `output` or `source_comparison`.", "minLength": 1 }, "page": { @@ -12647,7 +12647,7 @@ }, "format": { "type": "string", - "description": "Output format requested by the job. Required when multiple formats were requested, except for expectation observations.", + "description": "Requested output format this observation refers to. Required when the job requested multiple formats and `basis` is `output` or `source_comparison`.", "minLength": 1 }, "page": { @@ -12709,7 +12709,7 @@ }, "format": { "type": "string", - "description": "Output format requested by the job. Required when multiple formats were requested, except for expectation observations.", + "description": "Requested output format this observation refers to. Required when the job requested multiple formats and `basis` is `output` or `source_comparison`.", "minLength": 1 }, "page": { @@ -12771,7 +12771,7 @@ }, "format": { "type": "string", - "description": "Output format requested by the job. Required when multiple formats were requested, except for expectation observations.", + "description": "Requested output format this observation refers to. Required when the job requested multiple formats and `basis` is `output` or `source_comparison`.", "minLength": 1 }, "page": { From 3e53d54014da3c3a4d551238add8205a35a82ed8 Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Sun, 13 Sep 2026 21:27:50 -0500 Subject: [PATCH 14/25] docs: remove feedback limit detail from reference prose --- api-reference/endpoint/feedback.mdx | 2 -- api-reference/v2-openapi.json | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index 58940b4c0..5718f29e4 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -8,8 +8,6 @@ Submit feedback on the quality of a job's output, including useful results, miss For jobs created with an API key, include your key and use the Authenticated request format. For keyless jobs, omit `Authorization` and use the Search, Scrape, or Parse request format. -Keyless feedback is limited to one accepted submission per identity per UTC day across all three endpoints and clients. - ### Authenticated example ```bash diff --git a/api-reference/v2-openapi.json b/api-reference/v2-openapi.json index d964cde91..f7c323a46 100644 --- a/api-reference/v2-openapi.json +++ b/api-reference/v2-openapi.json @@ -6125,7 +6125,7 @@ } } }, - "description": "Submit feedback for a job. Keyless feedback supports Search, Scrape, and Parse. One accepted submission per keyless identity per UTC day, shared across these endpoints and clients." + "description": "Submit feedback for a job. Keyless feedback supports Search, Scrape, and Parse." } }, "/team/threat-protection": { From fa8b88835b02f88bdb8e040860f55a788bde7489 Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Sun, 13 Sep 2026 22:00:22 -0500 Subject: [PATCH 15/25] docs(api): align keyless feedback evidence contract --- api-reference/endpoint/feedback.mdx | 2 ++ api-reference/v2-openapi.json | 25 +++++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index 5718f29e4..e61f2fdca 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -8,6 +8,8 @@ Submit feedback on the quality of a job's output, including useful results, miss For jobs created with an API key, include your key and use the Authenticated request format. For keyless jobs, omit `Authorization` and use the Search, Scrape, or Parse request format. +Keyless Parse feedback does not automatically retain the document, extracted output, page images, or layout blocks. Submitted observations and corrections are retained. + ### Authenticated example ```bash diff --git a/api-reference/v2-openapi.json b/api-reference/v2-openapi.json index f7c323a46..607e325d1 100644 --- a/api-reference/v2-openapi.json +++ b/api-reference/v2-openapi.json @@ -11824,7 +11824,7 @@ }, "detail": { "type": "string", - "description": "How the source differs from the output.", + "description": "The correct content from the inspected source, including correct text or cell values when known.", "minLength": 10, "maxLength": 2000 } @@ -11889,7 +11889,7 @@ }, "observations": { "type": "array", - "description": "Specific observations about the result. Text limits exclude leading and trailing whitespace.", + "description": "Specific observations about the result. Text limits exclude leading and trailing whitespace. Unmentioned results are unassessed; a full ranking is not required.", "minItems": 1, "maxItems": 20, "items": { @@ -12025,6 +12025,16 @@ }, "comparison": { "$ref": "#/components/schemas/FeedbackComparison" + }, + "knownSources": { + "type": "array", + "description": "Known sources that should have ranked instead of this result.", + "maxItems": 20, + "items": { + "type": "string", + "format": "uri", + "pattern": "^https?://" + } } }, "required": [ @@ -12318,7 +12328,8 @@ "type": "string", "enum": [ "incomplete" - ] + ], + "description": "Prefer `source_comparison` when the source is already available, and provide the correct content in `comparison.detail`." }, "format": { "type": "string", @@ -12382,7 +12393,8 @@ "type": "string", "enum": [ "incorrect" - ] + ], + "description": "Prefer `source_comparison` when the source is already available, and provide the correct content in `comparison.detail`." }, "format": { "type": "string", @@ -12402,7 +12414,7 @@ "hallucinated", "missing_fields" ], - "description": "Reason for the issue." + "description": "Reason for the issue. `hallucinated` applies only to `json`, `deterministicJson`, `summary`, `question`, `highlights`, and `changeTracking` in `json` mode. `missing_fields` applies only to `json` and `deterministicJson`." }, "detail": { "$ref": "#/components/schemas/FeedbackDetail" @@ -12767,7 +12779,8 @@ "type": "string", "enum": [ "incorrect" - ] + ], + "description": "Incorrect `json` or `summary` output." }, "format": { "type": "string", From c5c9f8c12e97bcfaccfc8d9039c0776b2d0042b2 Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Thu, 17 Sep 2026 16:37:16 -0500 Subject: [PATCH 16/25] docs: define keyless feedback reasons and submission limits --- api-reference/endpoint/feedback.mdx | 21 ++++ api-reference/v2-openapi.json | 182 ++++++++++++++++++++++++++-- 2 files changed, 192 insertions(+), 11 deletions(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index e61f2fdca..2146b3dfc 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -48,3 +48,24 @@ curl -X POST "https://api.firecrawl.dev/v2/feedback" \ ] }' ``` + +### Keyless limits and failures + +Every eligible keyless Search, Scrape, or Parse response includes a feedback pointer and this documentation link. Use the returned job ID from the same caller IP within 24 hours. The default allowance is one accepted submission per caller IP per UTC day across all three endpoints and clients; the invitation states the deployment allowance. There are 30 submission attempts per minute, including rejected requests. Retrying a recorded submission returns its original feedback ID without using another daily slot. + +The serialized stored keyless metadata must fit within 8 KiB (8192 UTF-8 bytes), including server defaults and verification flags. Keep observations concise and omit raw outputs. + +For Search, positions refer to the ordered results in the delivered `web`, `images`, or `news` group. Specify `source` for multi-source jobs and for images-only or news-only jobs; omission defaults to `web`. If the saved Search response is unavailable, otherwise valid feedback is accepted with an internal `metadata.unverified: true` marker because positions could not be checked. Ownership and requested sources are still checked. Invalid positions in available results are rejected. + +An explicitly failed job can receive a `failure` observation. Use the reported error, without diagnosing an unobserved cause. For example, replace the observation in your submission with: + +```json +{ + "kind": "failure", + "reason": "timeout", + "basis": "output", + "detail": "The operation returned a timeout before producing a result." +} +``` + +A failure observation has no position, source, format, location, or page. Parse still requires a top-level `docClass`, which may be `unknown`. The API accepts this observation only for a saved failed job. Requests rejected before execution, such as invalid input or exhausted operation quota, are not feedback jobs. diff --git a/api-reference/v2-openapi.json b/api-reference/v2-openapi.json index 607e325d1..8bab6c657 100644 --- a/api-reference/v2-openapi.json +++ b/api-reference/v2-openapi.json @@ -11910,7 +11910,7 @@ "images", "news" ], - "description": "Result group the position refers to. Required when the search requested multiple sources. Defaults to `web` otherwise." + "description": "Delivered group the position refers to. Required for multi-source jobs. Omission defaults to `web`, so images-only and news-only jobs must explicitly name their source." }, "position": { "type": "integer", @@ -11982,7 +11982,7 @@ "images", "news" ], - "description": "Result group the position refers to. Required when the search requested multiple sources. Defaults to `web` otherwise." + "description": "Delivered group the position refers to. Required for multi-source jobs. Omission defaults to `web`, so images-only and news-only jobs must explicitly name their source." }, "position": { "type": "integer", @@ -12015,7 +12015,7 @@ "snippet_misleading", "blocked_or_paywalled" ], - "description": "Reason for the issue." + "description": "- `aggregator_over_official`: An intermediary was returned where the task needed an available official or primary source.\n- `off_topic`: The result addresses a different topic from the task.\n- `stale`: The content is outdated for the time or version the task requires.\n- `wrong_content_type`: The destination has the wrong content type for the task, such as a discussion instead of a reference.\n- `snippet_misleading`: The returned description misrepresents source content already inspected.\n- `blocked_or_paywalled`: Access to the destination was observed to be blocked or require a subscription; do not infer this from its URL or snippet." }, "detail": { "$ref": "#/components/schemas/FeedbackDetail" @@ -12133,6 +12133,59 @@ ] } } + }, + { + "type": "object", + "title": "failure", + "description": "An explicitly reported failure of this job. Accepted only when the saved job failed. No result position or output format is required.", + "properties": { + "kind": { + "type": "string", + "enum": [ + "failure" + ] + }, + "reason": { + "type": "string", + "enum": [ + "timeout", + "transport_error", + "proxy_error", + "other" + ], + "description": "- `timeout`: The operation explicitly reported a timeout.\n- `transport_error`: The operation explicitly reported a network, connection, or TLS failure.\n- `proxy_error`: The operation explicitly reported a proxy failure.\n- `other`: Another operation failure was reported; describe the returned error without guessing its cause." + }, + "detail": { + "$ref": "#/components/schemas/FeedbackDetail" + }, + "basis": { + "$ref": "#/components/schemas/FeedbackBasis" + }, + "comparison": { + "$ref": "#/components/schemas/FeedbackComparison" + } + }, + "required": [ + "kind", + "reason", + "detail", + "basis" + ], + "additionalProperties": false, + "not": { + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] + } + }, + "not": { + "required": [ + "comparison" + ] + } + } } ] } @@ -12286,7 +12339,7 @@ "stale", "wrong_locale" ], - "description": "Reason for the issue." + "description": "- `blocked_shell`: The successful response contains a bot challenge or access-blocking shell instead of the requested content.\n- `login_required`: The successful response contains a login requirement instead of the requested content.\n- `paywall`: The successful response contains a subscription barrier instead of the requested content.\n- `empty`: The successful response contains no meaningful requested content.\n- `wrong_page`: The successful response contains a different page or resource.\n- `stale`: The content is outdated for the time or version the task requires.\n- `wrong_locale`: The response uses the wrong language or region for the task." }, "detail": { "$ref": "#/components/schemas/FeedbackDetail" @@ -12351,7 +12404,7 @@ "main_content_stripped", "format_lost" ], - "description": "Reason for the issue." + "description": "- `partial_content`: Only part of the expected content was returned, without a more specific known cause.\n- `dynamic_content`: Content loaded by client-side rendering or interaction is missing.\n- `pagination`: Expected content on additional pages is missing.\n- `main_content_stripped`: Content filtering removed requested primary content.\n- `format_lost`: Text is present, but meaningful structure such as headings, lists, or code formatting was lost." }, "detail": { "$ref": "#/components/schemas/FeedbackDetail" @@ -12414,7 +12467,7 @@ "hallucinated", "missing_fields" ], - "description": "Reason for the issue. `hallucinated` applies only to `json`, `deterministicJson`, `summary`, `question`, `highlights`, and `changeTracking` in `json` mode. `missing_fields` applies only to `json` and `deterministicJson`." + "description": "- `wrong`: Returned facts or values conflict with the inspected source.\n- `hallucinated`: The output asserts content unsupported by the inspected source.\n- `missing_fields`: Requested fields are absent from the structured output.\n\n`hallucinated` applies only to `json`, `deterministicJson`, `summary`, `question`, `highlights`, and `changeTracking` in `json` mode. `missing_fields` applies only to `json` and `deterministicJson`." }, "detail": { "$ref": "#/components/schemas/FeedbackDetail" @@ -12448,6 +12501,59 @@ ] } } + }, + { + "type": "object", + "title": "failure", + "description": "An explicitly reported failure of this job. Accepted only when the saved job failed. No result position or output format is required.", + "properties": { + "kind": { + "type": "string", + "enum": [ + "failure" + ] + }, + "reason": { + "type": "string", + "enum": [ + "timeout", + "transport_error", + "proxy_error", + "other" + ], + "description": "- `timeout`: The operation explicitly reported a timeout.\n- `transport_error`: The operation explicitly reported a network, connection, or TLS failure.\n- `proxy_error`: The operation explicitly reported a proxy failure.\n- `other`: Another operation failure was reported; describe the returned error without guessing its cause." + }, + "detail": { + "$ref": "#/components/schemas/FeedbackDetail" + }, + "basis": { + "$ref": "#/components/schemas/FeedbackBasis" + }, + "comparison": { + "$ref": "#/components/schemas/FeedbackComparison" + } + }, + "required": [ + "kind", + "reason", + "detail", + "basis" + ], + "additionalProperties": false, + "not": { + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] + } + }, + "not": { + "required": [ + "comparison" + ] + } + } } ] } @@ -12613,7 +12719,7 @@ "garbled", "missing_text" ], - "description": "Reason for the issue." + "description": "- `misread_chars`: Characters were recognized incorrectly.\n- `garbled`: Extracted text is corrupted or unreadable.\n- `missing_text`: Visible source text was omitted." }, "detail": { "$ref": "#/components/schemas/FeedbackDetail" @@ -12675,7 +12781,7 @@ "cells_glued", "digits" ], - "description": "Reason for the issue." + "description": "- `structure`: Table rows, columns, or header relationships were reconstructed incorrectly.\n- `cells_glued`: Distinct table cells were merged.\n- `digits`: Numeric table values were recognized incorrectly." }, "detail": { "$ref": "#/components/schemas/FeedbackDetail" @@ -12737,7 +12843,7 @@ "truncated_at_max_pages", "sections_dropped" ], - "description": "Reason for the issue." + "description": "- `pages_missing`: Source pages are absent from the output.\n- `truncated_at_max_pages`: Extraction ended at the configured page limit; this does not by itself imply a parser error.\n- `sections_dropped`: Sections within processed pages were omitted." }, "detail": { "$ref": "#/components/schemas/FeedbackDetail" @@ -12800,7 +12906,7 @@ "hallucinated", "missing_fields" ], - "description": "Reason for the issue." + "description": "- `wrong`: Returned facts or values conflict with the inspected source.\n- `hallucinated`: The output asserts content unsupported by the inspected source.\n- `missing_fields`: Requested fields are absent from the structured output." }, "detail": { "$ref": "#/components/schemas/FeedbackDetail" @@ -12834,6 +12940,59 @@ ] } } + }, + { + "type": "object", + "title": "failure", + "description": "An explicitly reported failure of this job. Accepted only when the saved job failed. No result position or output format is required.", + "properties": { + "kind": { + "type": "string", + "enum": [ + "failure" + ] + }, + "reason": { + "type": "string", + "enum": [ + "timeout", + "transport_error", + "proxy_error", + "other" + ], + "description": "- `timeout`: The operation explicitly reported a timeout.\n- `transport_error`: The operation explicitly reported a network, connection, or TLS failure.\n- `proxy_error`: The operation explicitly reported a proxy failure.\n- `other`: Another operation failure was reported; describe the returned error without guessing its cause." + }, + "detail": { + "$ref": "#/components/schemas/FeedbackDetail" + }, + "basis": { + "$ref": "#/components/schemas/FeedbackBasis" + }, + "comparison": { + "$ref": "#/components/schemas/FeedbackComparison" + } + }, + "required": [ + "kind", + "reason", + "detail", + "basis" + ], + "additionalProperties": false, + "not": { + "properties": { + "basis": { + "enum": [ + "source_comparison" + ] + } + }, + "not": { + "required": [ + "comparison" + ] + } + } } ] } @@ -12863,7 +13022,8 @@ "additionalProperties": false, "title": "Parse" } - ] + ], + "description": "Feedback for keyless jobs within 24 hours, submitted from the same caller IP. The serialized stored metadata, including server defaults and verification flags, must fit within 8 KiB (8192 UTF-8 bytes). The daily allowance defaults to one accepted submission per caller IP across Search, Scrape, Parse, and all clients; deployments may configure a different allowance. Submission attempts are limited to 30 per minute, including rejected requests. Duplicate submissions return the original record without using another daily slot." } } }, From ee81e313596ebb8d5dafafe45ebd40201c6deaa8 Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Wed, 23 Sep 2026 10:29:58 -0500 Subject: [PATCH 17/25] docs: describe keyless feedback as one submission per job Remove the daily submission allowance and the exact attempt rate from the feedback reference and OpenAPI description. Each job accepts one submission, retries return the original record, and attempts are rate limited. --- api-reference/endpoint/feedback.mdx | 2 +- api-reference/v2-openapi.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index 2146b3dfc..d631cf060 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -51,7 +51,7 @@ curl -X POST "https://api.firecrawl.dev/v2/feedback" \ ### Keyless limits and failures -Every eligible keyless Search, Scrape, or Parse response includes a feedback pointer and this documentation link. Use the returned job ID from the same caller IP within 24 hours. The default allowance is one accepted submission per caller IP per UTC day across all three endpoints and clients; the invitation states the deployment allowance. There are 30 submission attempts per minute, including rejected requests. Retrying a recorded submission returns its original feedback ID without using another daily slot. +Every eligible keyless Search, Scrape, or Parse response includes a feedback pointer and this documentation link. Use the returned job ID from the same caller IP within 24 hours. Each job accepts one submission; retrying a recorded submission returns its original feedback ID. Submission attempts are rate limited, so wait before retrying a `429` response. The serialized stored keyless metadata must fit within 8 KiB (8192 UTF-8 bytes), including server defaults and verification flags. Keep observations concise and omit raw outputs. diff --git a/api-reference/v2-openapi.json b/api-reference/v2-openapi.json index 8bab6c657..62a1b520e 100644 --- a/api-reference/v2-openapi.json +++ b/api-reference/v2-openapi.json @@ -13023,7 +13023,7 @@ "title": "Parse" } ], - "description": "Feedback for keyless jobs within 24 hours, submitted from the same caller IP. The serialized stored metadata, including server defaults and verification flags, must fit within 8 KiB (8192 UTF-8 bytes). The daily allowance defaults to one accepted submission per caller IP across Search, Scrape, Parse, and all clients; deployments may configure a different allowance. Submission attempts are limited to 30 per minute, including rejected requests. Duplicate submissions return the original record without using another daily slot." + "description": "Feedback for keyless jobs within 24 hours, submitted from the same caller IP. The serialized stored metadata, including server defaults and verification flags, must fit within 8 KiB (8192 UTF-8 bytes). Each job accepts one submission; duplicate submissions return the original record. Submission attempts are rate limited." } } }, From 2eebb344746f95f1585924c402719fc254407ed8 Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Wed, 23 Sep 2026 14:15:31 -0500 Subject: [PATCH 18/25] docs(api): simplify keyless feedback guidance --- api-reference/endpoint/feedback.mdx | 16 ++++++++-------- api-reference/v2-openapi.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index d631cf060..730792c9c 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -8,8 +8,6 @@ Submit feedback on the quality of a job's output, including useful results, miss For jobs created with an API key, include your key and use the Authenticated request format. For keyless jobs, omit `Authorization` and use the Search, Scrape, or Parse request format. -Keyless Parse feedback does not automatically retain the document, extracted output, page images, or layout blocks. Submitted observations and corrections are retained. - ### Authenticated example ```bash @@ -49,15 +47,17 @@ curl -X POST "https://api.firecrawl.dev/v2/feedback" \ }' ``` -### Keyless limits and failures +### Keyless feedback -Every eligible keyless Search, Scrape, or Parse response includes a feedback pointer and this documentation link. Use the returned job ID from the same caller IP within 24 hours. Each job accepts one submission; retrying a recorded submission returns its original feedback ID. Submission attempts are rate limited, so wait before retrying a `429` response. +Eligible keyless Search, Scrape, and Parse responses include a job ID and a feedback invitation. Submit feedback within 24 hours from the same IP address used for the job. Each job accepts one submission; retrying returns the original feedback ID. If you receive a `429`, wait before retrying. -The serialized stored keyless metadata must fit within 8 KiB (8192 UTF-8 bytes), including server defaults and verification flags. Keep observations concise and omit raw outputs. +Keep observations concise and avoid copying full results. + +Keyless Parse feedback does not automatically retain the document, extracted output, page images, or layout blocks. Submitted observations and corrections are retained. -For Search, positions refer to the ordered results in the delivered `web`, `images`, or `news` group. Specify `source` for multi-source jobs and for images-only or news-only jobs; omission defaults to `web`. If the saved Search response is unavailable, otherwise valid feedback is accepted with an internal `metadata.unverified: true` marker because positions could not be checked. Ownership and requested sources are still checked. Invalid positions in available results are rejected. +For Search, `position` starts at 1 within the returned `web`, `images`, or `news` results. Set `source` for `images`, `news`, or a search with multiple sources; otherwise it defaults to `web`. Report positions that appear in the response. -An explicitly failed job can receive a `failure` observation. Use the reported error, without diagnosing an unobserved cause. For example, replace the observation in your submission with: +If a failed response includes a feedback invitation, use the reported error in a `failure` observation: ```json { @@ -68,4 +68,4 @@ An explicitly failed job can receive a `failure` observation. Use the reported e } ``` -A failure observation has no position, source, format, location, or page. Parse still requires a top-level `docClass`, which may be `unknown`. The API accepts this observation only for a saved failed job. Requests rejected before execution, such as invalid input or exhausted operation quota, are not feedback jobs. +For failures, omit result-specific fields such as `position`, `format`, or `page`. Parse still requires `docClass`, which may be `unknown`. Requests rejected before execution, such as invalid input or exhausted operation quota, have no feedback job. diff --git a/api-reference/v2-openapi.json b/api-reference/v2-openapi.json index 62a1b520e..064d9efdb 100644 --- a/api-reference/v2-openapi.json +++ b/api-reference/v2-openapi.json @@ -13023,7 +13023,7 @@ "title": "Parse" } ], - "description": "Feedback for keyless jobs within 24 hours, submitted from the same caller IP. The serialized stored metadata, including server defaults and verification flags, must fit within 8 KiB (8192 UTF-8 bytes). Each job accepts one submission; duplicate submissions return the original record. Submission attempts are rate limited." + "description": "Feedback for a keyless Search, Scrape, or Parse job. Submit within 24 hours from the same IP address used for the job. Each job accepts one submission; retrying returns the original feedback ID. Keep observations concise; feedback over 8 KiB is rejected." } } }, From ca33990dd97fe9eec81b72cae1aca52e85ea4d8b Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Wed, 23 Sep 2026 15:14:07 -0500 Subject: [PATCH 19/25] docs(api): declare the known source URL length limit The keyless feedback API caps each knownSources URL at 2048 characters, matching the comparison reference. --- api-reference/v2-openapi.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/api-reference/v2-openapi.json b/api-reference/v2-openapi.json index 064d9efdb..b9dcc4935 100644 --- a/api-reference/v2-openapi.json +++ b/api-reference/v2-openapi.json @@ -12033,7 +12033,8 @@ "items": { "type": "string", "format": "uri", - "pattern": "^https?://" + "pattern": "^https?://", + "maxLength": 2048 } } }, @@ -12098,7 +12099,8 @@ "items": { "type": "string", "format": "uri", - "pattern": "^https?://" + "pattern": "^https?://", + "maxLength": 2048 } }, "detail": { From a70335cc225ecc644ef8cde8baeb19f74e9b0a8b Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Wed, 23 Sep 2026 18:04:13 -0500 Subject: [PATCH 20/25] docs(api): require a non-empty keyless feedback origin Declare minLength 1 for origin, matching the API validation. --- api-reference/v2-openapi.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api-reference/v2-openapi.json b/api-reference/v2-openapi.json index b9dcc4935..51f090503 100644 --- a/api-reference/v2-openapi.json +++ b/api-reference/v2-openapi.json @@ -12195,6 +12195,7 @@ "origin": { "type": "string", "description": "Client submitting the feedback.", + "minLength": 1, "maxLength": 100, "default": "api" }, @@ -12563,6 +12564,7 @@ "origin": { "type": "string", "description": "Client submitting the feedback.", + "minLength": 1, "maxLength": 100, "default": "api" }, @@ -13002,6 +13004,7 @@ "origin": { "type": "string", "description": "Client submitting the feedback.", + "minLength": 1, "maxLength": 100, "default": "api" }, From 9387f30559e35916b71007479d38c4070b840eff Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Thu, 1 Oct 2026 11:07:50 -0500 Subject: [PATCH 21/25] docs(feedback): align keyless guidance with the API contract --- api-reference/endpoint/feedback.mdx | 10 ++++++++-- api-reference/v2-openapi.json | 23 +++++++++++++++++------ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index 730792c9c..11d3b2054 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -49,9 +49,15 @@ curl -X POST "https://api.firecrawl.dev/v2/feedback" \ ### Keyless feedback -Eligible keyless Search, Scrape, and Parse responses include a job ID and a feedback invitation. Submit feedback within 24 hours from the same IP address used for the job. Each job accepts one submission; retrying returns the original feedback ID. If you receive a `429`, wait before retrying. +Feedback is optional and does not affect continued keyless access or consume operation allowance. The API invitation says: -Keep observations concise and avoid copying full results. +> Consider submitting feedback to POST /v2/feedback, especially if this result is wrong, incomplete, blocked, or an error. Include specific evidence to help improve Firecrawl. + +Use evidence already available from the task; no extra investigation or user interview is required. + +Eligible keyless Search, Scrape, and Parse responses include a job ID and a feedback invitation. Search returns them in `metadata`; successful Scrape and Parse calls return them in `data.metadata`. Failed jobs return them in `metadata`. The invitation includes `jobId`, `endpoint`, and `expiresAt`. Submit feedback within 24 hours from the same IP address used for the job. Each job accepts one submission; retrying returns the original feedback ID. If you receive a `429`, wait before retrying. + +Keep observations concise and avoid copying full results. Text limits apply after trimming leading and trailing whitespace. Keyless Parse feedback does not automatically retain the document, extracted output, page images, or layout blocks. Submitted observations and corrections are retained. diff --git a/api-reference/v2-openapi.json b/api-reference/v2-openapi.json index fbc87c15e..899c11987 100644 --- a/api-reference/v2-openapi.json +++ b/api-reference/v2-openapi.json @@ -12222,6 +12222,11 @@ "items": { "type": "object" } + }, + "retry_after_seconds": { + "type": "integer", + "minimum": 1, + "description": "Seconds to wait before retrying a throttled feedback submission." } }, "required": [ @@ -12671,9 +12676,11 @@ }, "integration": { "type": "string", - "description": "Integration submitting the feedback.", + "description": "Supported integration name, or a custom name beginning with `_`.", "maxLength": 100, - "nullable": true + "nullable": true, + "minLength": 1, + "pattern": "^(?:_|(?:dify|zapier|pipedream|raycast|langchain|crewai|llamaindex|n8n|camelai|make|flowise|metagpt|relevanceai|viasocket|cli|hermes|gstack|prometheus)$)" } }, "required": [ @@ -13040,9 +13047,11 @@ }, "integration": { "type": "string", - "description": "Integration submitting the feedback.", + "description": "Supported integration name, or a custom name beginning with `_`.", "maxLength": 100, - "nullable": true + "nullable": true, + "minLength": 1, + "pattern": "^(?:_|(?:dify|zapier|pipedream|raycast|langchain|crewai|llamaindex|n8n|camelai|make|flowise|metagpt|relevanceai|viasocket|cli|hermes|gstack|prometheus)$)" } }, "required": [ @@ -13480,9 +13489,11 @@ }, "integration": { "type": "string", - "description": "Integration submitting the feedback.", + "description": "Supported integration name, or a custom name beginning with `_`.", "maxLength": 100, - "nullable": true + "nullable": true, + "minLength": 1, + "pattern": "^(?:_|(?:dify|zapier|pipedream|raycast|langchain|crewai|llamaindex|n8n|camelai|make|flowise|metagpt|relevanceai|viasocket|cli|hermes|gstack|prometheus)$)" } }, "required": [ From da00b4245bd09789ff6f79a9234db6b7ac9861fe Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Thu, 1 Oct 2026 11:20:18 -0500 Subject: [PATCH 22/25] docs(feedback): make keyless evidence readable without request tabs --- api-reference/endpoint/feedback.mdx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index 11d3b2054..6dd7633d4 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -49,15 +49,19 @@ curl -X POST "https://api.firecrawl.dev/v2/feedback" \ ### Keyless feedback -Feedback is optional and does not affect continued keyless access or consume operation allowance. The API invitation says: +Feedback is optional and does not affect continued keyless access or consume operation allowance. It remains available after the operation allowance is exhausted. The API invitation says: > Consider submitting feedback to POST /v2/feedback, especially if this result is wrong, incomplete, blocked, or an error. Include specific evidence to help improve Firecrawl. Use evidence already available from the task; no extra investigation or user interview is required. -Eligible keyless Search, Scrape, and Parse responses include a job ID and a feedback invitation. Search returns them in `metadata`; successful Scrape and Parse calls return them in `data.metadata`. Failed jobs return them in `metadata`. The invitation includes `jobId`, `endpoint`, and `expiresAt`. Submit feedback within 24 hours from the same IP address used for the job. Each job accepts one submission; retrying returns the original feedback ID. If you receive a `429`, wait before retrying. +Eligible keyless Search, Scrape, and Parse responses include a job ID and a feedback invitation. Search returns them in `metadata`; successful Scrape and Parse calls return them in `data.metadata`. Failed jobs return them in `metadata`. The invitation includes `jobId`, `endpoint`, and `expiresAt`. Submit feedback within 24 hours from the same IP address used for the job. Each job accepts one submission; retrying returns the original feedback ID. If you receive a `429`, wait for `retry_after_seconds` before retrying. -Keep observations concise and avoid copying full results. Text limits apply after trimming leading and trailing whitespace. +Keyless requests require `endpoint`, `jobId`, `rating` (`good`, `partial`, or `bad`), `task`, `assessment`, and 1-20 `observations`. Each observation requires `kind`, `detail`, and `basis` (`output`, `source_comparison`, or `expectation`). Source comparisons also require `comparison: {reference, detail}`, describing the correct content from a source already inspected. Parse additionally requires `docClass`: `born_digital`, `scanned`, `mixed`, or `unknown`. + +`task`, `assessment`, and each `detail` must contain 10-2000 characters after trimming leading and trailing whitespace. For Scrape and Parse observations other than failures, `format` must name a requested format. Include it when multiple formats were requested and the basis is `output` or `source_comparison`. + +Keep observations concise and avoid copying full results. Stored feedback must fit within 8 KiB (8192 UTF-8 bytes), including server defaults and verification flags. The [OpenAPI schema](/api-reference/v2-openapi.json) lists each endpoint's observation kinds and reason codes. Keyless Parse feedback does not automatically retain the document, extracted output, page images, or layout blocks. Submitted observations and corrections are retained. From 3d3021981358274634e1c930cf7c0a3e89c7dac3 Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Thu, 1 Oct 2026 11:49:39 -0500 Subject: [PATCH 23/25] docs(feedback): retain authenticated Search guidance --- api-reference/endpoint/feedback.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index 6dd7633d4..89a89315a 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -8,6 +8,8 @@ Submit feedback on the quality of a job's output, including useful results, miss For jobs created with an API key, include your key and use the Authenticated request format. For keyless jobs, omit `Authorization` and use the Search, Scrape, or Parse request format. +For authenticated Search jobs, [Search Feedback](/api-reference/endpoint/search-feedback) remains the preferred search-specific entry point for valuable sources, missing content, query suggestions, and refund behavior. + ### Authenticated example ```bash From 69f906d33823a59626dbcee2fc6330623b4ab62c Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Fri, 2 Oct 2026 22:22:27 -0500 Subject: [PATCH 24/25] docs: clarify the keyless feedback submission deadline --- api-reference/endpoint/feedback.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index 89a89315a..6c3339b62 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -57,7 +57,7 @@ Feedback is optional and does not affect continued keyless access or consume ope Use evidence already available from the task; no extra investigation or user interview is required. -Eligible keyless Search, Scrape, and Parse responses include a job ID and a feedback invitation. Search returns them in `metadata`; successful Scrape and Parse calls return them in `data.metadata`. Failed jobs return them in `metadata`. The invitation includes `jobId`, `endpoint`, and `expiresAt`. Submit feedback within 24 hours from the same IP address used for the job. Each job accepts one submission; retrying returns the original feedback ID. If you receive a `429`, wait for `retry_after_seconds` before retrying. +Eligible keyless Search, Scrape, and Parse responses include a job ID and a feedback invitation. Search returns them in `metadata`; successful Scrape and Parse calls return them in `data.metadata`. Failed jobs return them in `metadata`. The invitation includes `jobId`, `endpoint`, and `expiresAt`. Submit from the same IP address used for the job before the invitation's `expiresAt` deadline, which provides a 24-hour feedback window for the job. Each job accepts one submission; retrying returns the original feedback ID. If you receive a `429`, wait for `retry_after_seconds` before retrying. Keyless requests require `endpoint`, `jobId`, `rating` (`good`, `partial`, or `bad`), `task`, `assessment`, and 1-20 `observations`. Each observation requires `kind`, `detail`, and `basis` (`output`, `source_comparison`, or `expectation`). Source comparisons also require `comparison: {reference, detail}`, describing the correct content from a source already inspected. Parse additionally requires `docClass`: `born_digital`, `scanned`, `mixed`, or `unknown`. From 878c8b13edfe0124dd00894fcdb849d14295b8ba Mon Sep 17 00:00:00 2001 From: Max Loffgren Date: Thu, 8 Oct 2026 11:35:46 -0500 Subject: [PATCH 25/25] docs: clarify keyless feedback retry guarantees --- api-reference/endpoint/feedback.mdx | 2 +- api-reference/v2-openapi.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api-reference/endpoint/feedback.mdx b/api-reference/endpoint/feedback.mdx index 6c3339b62..ce5faad6c 100644 --- a/api-reference/endpoint/feedback.mdx +++ b/api-reference/endpoint/feedback.mdx @@ -57,7 +57,7 @@ Feedback is optional and does not affect continued keyless access or consume ope Use evidence already available from the task; no extra investigation or user interview is required. -Eligible keyless Search, Scrape, and Parse responses include a job ID and a feedback invitation. Search returns them in `metadata`; successful Scrape and Parse calls return them in `data.metadata`. Failed jobs return them in `metadata`. The invitation includes `jobId`, `endpoint`, and `expiresAt`. Submit from the same IP address used for the job before the invitation's `expiresAt` deadline, which provides a 24-hour feedback window for the job. Each job accepts one submission; retrying returns the original feedback ID. If you receive a `429`, wait for `retry_after_seconds` before retrying. +Eligible keyless Search, Scrape, and Parse responses include a job ID and a feedback invitation. Search returns them in `metadata`; successful Scrape and Parse calls return them in `data.metadata`. Failed jobs return them in `metadata`. The invitation includes `jobId`, `endpoint`, and `expiresAt`. Submit from the same IP address used for the job before the invitation's `expiresAt` deadline, which provides a 24-hour feedback window for the job. Each job accepts one submission; retrying a successful submission within the feedback window returns its original feedback ID. If you receive a `429`, wait for `retry_after_seconds` before retrying. Keyless requests require `endpoint`, `jobId`, `rating` (`good`, `partial`, or `bad`), `task`, `assessment`, and 1-20 `observations`. Each observation requires `kind`, `detail`, and `basis` (`output`, `source_comparison`, or `expectation`). Source comparisons also require `comparison: {reference, detail}`, describing the correct content from a source already inspected. Parse additionally requires `docClass`: `born_digital`, `scanned`, `mixed`, or `unknown`. diff --git a/api-reference/v2-openapi.json b/api-reference/v2-openapi.json index 3d2ee79ec..15dd84b28 100644 --- a/api-reference/v2-openapi.json +++ b/api-reference/v2-openapi.json @@ -14261,7 +14261,7 @@ "title": "Parse" } ], - "description": "Feedback for a keyless Search, Scrape, or Parse job. Submit within 24 hours from the same IP address used for the job. Each job accepts one submission; retrying returns the original feedback ID. Keep observations concise; feedback over 8 KiB is rejected." + "description": "Feedback for a keyless Search, Scrape, or Parse job. Submit within 24 hours from the same IP address used for the job. Each job accepts one submission; retrying a successful submission within the feedback window returns its original feedback ID. Keep observations concise; feedback over 8 KiB is rejected." }, "AgentPendingApproval": { "type": "object",