# Check quotes in a batch

Check whether each quote appears in the source you provide.

Documentation index: https://webcite.co/llms.txt
Canonical page: https://webcite.co/api-docs/batch
API origin: https://api.webcite.co
Authentication: x-api-key header. Keep keys on your server.

## When to use it

This checks source grounding. It does not independently search for evidence that the quoted assertion is true. Provide `source_text`, `url`, or `asset_id` for each quote. For retained evidence, supply all three immutable IDs: `source_version_id`, `representation_id`, and `source_unit_id`.

`fuzzy` and `reflowed` matches remain `needs_review`. Omit `meaning` when no assessment is available; the result reports `not_checked`. Caller-supplied `meaning` accepts only `changed` or `ambiguous`, never a self-certified `faithful`.

## Per-item response example

Illustrative response, not a recorded API result.

```json
[
  {
    "id": "1",
    "quote": "reduced HbA1c by 1.2%",
    "binding": {
      "grounded": true,
      "method": "fuzzy",
      "score": 0.67,
      "matched_text": "A 1.2% reduction in HbA1c was observed versus placebo."
    },
    "verification": {
      "layer": "bound",
      "band": "needs_review",
      "confidence": 80,
      "grounded": true,
      "meaning": "not_checked"
    },
    "feedback_token": "eyJxIjoi..."
  }
]
```

## Prepared OCR example

Illustrative response, not a recorded API result.

```json
[
  {
    "id": "ocr-example",
    "quote": "Revenue increased by 18 percent.",
    "binding": {
      "grounded": true,
      "method": "reflowed",
      "reading": "body",
      "score": 1,
      "matched_text": "Revenue increased\nAnnual report\nby 18 percent.",
      "rescue": {
        "attempted": true,
        "rescued": true,
        "reading": "Revenue increased by 18 percent.",
        "transformations": [
          {
            "kind": "drop",
            "atLine": 1,
            "line": "Annual report",
            "source": "element_label"
          },
          {
            "kind": "join",
            "afterLine": 0
          }
        ],
        "droppedLines": [
          "Annual report"
        ],
        "retainedSpans": [
          {
            "page": 1,
            "fromLine": 0,
            "toLine": 0
          },
          {
            "page": 1,
            "fromLine": 2,
            "toLine": 2
          }
        ],
        "calibrationKey": "illustrative-prepared-artifact-key",
        "basis": "code",
        "model": null,
        "decidedAt": "2026-09-19T00:00:00.000Z"
      }
    },
    "verification": {
      "layer": "bound",
      "band": "needs_review",
      "confidence": 80,
      "grounded": true,
      "meaning": "not_checked"
    },
    "feedback_token": "illustrative-token"
  }
]
```

## Request

POST /api/v1/verify/batch

1 credit per item, up to 200 items.

### curl

```curl
curl --fail-with-body -X POST 'https://api.webcite.co/api/v1/verify/batch' \
  -H "x-api-key: $WEBCITE_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
  "items": [
    {
      "id": "revenue-2025",
      "quote": "Revenue was $12 million.",
      "source_text": "The annual report states: Revenue was $12 million."
    }
  ]
}'
```

### Node.js

```javascript
const response = await fetch("https://api.webcite.co/api/v1/verify/batch", {
  method: "POST",
  headers: {
    "x-api-key": process.env.WEBCITE_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
  "items": [
    {
      "id": "revenue-2025",
      "quote": "Revenue was $12 million.",
      "source_text": "The annual report states: Revenue was $12 million."
    }
  ]
}),
});
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
console.log(await response.json());
```

### python

```python
import os
import json
import requests

payload = json.loads("{\n  \"items\": [\n    {\n      \"id\": \"revenue-2025\",\n      \"quote\": \"Revenue was $12 million.\",\n      \"source_text\": \"The annual report states: Revenue was $12 million.\"\n    }\n  ]\n}")
response = requests.post(
    "https://api.webcite.co/api/v1/verify/batch",
    headers={"x-api-key": os.environ["WEBCITE_API_KEY"]},
    json=payload,
    timeout=(10, 300),
)
response.raise_for_status()
print(response.json())
```

## Response

An array of results, one per item. Each result includes binding, verification, and feedback_token. This endpoint returns an array, not an object with a top-level usage receipt.

## Errors

For 400, check the request fields and source identifiers. For 401, check your API key. For 429, wait for the retry interval. See the errors guide before retrying a billable request.

## OpenAPI operation

```json
{
  "path": "/api/v1/verify/batch",
  "method": "POST",
  "operation": {
    "description": "Bind every claim to its source in a single request. Each item is a quote plus its source (inline text, a url, or an asset). The response gives, per item, whether the quote is grounded, how it matched (exact, normalized, fuzzy, reflowed, or unbound), the best-matching passage and score even when unbound, the verification tier, and a feedback token.\n\nA fuzzy match is capped at needs_review, never verified. A reflowed match uses a derived OCR reading and is also capped at needs_review. Use this to check every citation in a document at once.\n\n**Cost: 1 credit per item.** BindBack is deterministic (no LLM calls), but a batch can be large and `url`/`asset` items fetch their source, so this endpoint is rate-limited more strictly than compute-only endpoints.",
    "operationId": "ApiV1Controller_verifyBatch",
    "parameters": [],
    "requestBody": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/VerifyBatchRequestDto"
          }
        }
      },
      "required": true
    },
    "responses": {
      "200": {
        "content": {
          "application/json": {
            "schema": {
              "items": {
                "$ref": "#/components/schemas/VerifyBatchResultDto"
              },
              "type": "array"
            }
          }
        },
        "description": "Per-item verification results"
      },
      "401": {
        "description": "Unauthorized - API key required"
      },
      "429": {
        "description": "Rate limit exceeded"
      }
    },
    "security": [
      {
        "x-api-key": []
      },
      {
        "bearer": []
      }
    ],
    "summary": "Verify many claims in one call",
    "tags": [
      "Public API"
    ]
  },
  "schemas": {
    "VerifyBatchRequestDto": {
      "properties": {
        "items": {
          "description": "Claims to verify, each against its source. Bound back per item; a fuzzy match is capped at needs_review, never verified.",
          "items": {
            "$ref": "#/components/schemas/BatchItemDto"
          },
          "type": "array"
        }
      },
      "required": [
        "items"
      ],
      "type": "object"
    },
    "BatchItemDto": {
      "properties": {
        "asset_id": {
          "description": "An uploaded asset id to check against.",
          "type": "string"
        },
        "id": {
          "description": "Caller id echoed back on the result.",
          "type": "string"
        },
        "meaning": {
          "description": "A meaning-preservation problem you have already found, from an assessment such as POST /api/v2/context/assess-meaning. Only the cautious states are accepted: \"changed\" and \"ambiguous\" stop a citation presenting as verified. \"faithful\" is deliberately NOT accepted here — a clearance asserted by the party asking for the check is not a check, and this field exists precisely so that \"nobody assessed this\" cannot be mistaken for \"an assessor cleared this\". Omit it when you found no problem; the result then reports meaning \"not_checked\", which is what absence honestly means.",
          "enum": [
            "changed",
            "ambiguous"
          ],
          "type": "string"
        },
        "page": {
          "description": "1-based page for an asset source.",
          "type": "number"
        },
        "quote": {
          "description": "The claim or quote to check.",
          "type": "string"
        },
        "representation_id": {
          "type": "string"
        },
        "source_text": {
          "description": "The source text to check the quote against. Provide this, or url, or asset_id.",
          "type": "string"
        },
        "source_unit_id": {
          "type": "string"
        },
        "source_version_id": {
          "description": "Immutable source version. Requires exact representation and unit IDs.",
          "type": "string"
        },
        "url": {
          "description": "A web source URL to resolve and check.",
          "type": "string"
        }
      },
      "required": [
        "quote"
      ],
      "type": "object"
    },
    "VerifyBatchResultDto": {
      "properties": {
        "binding": {
          "$ref": "#/components/schemas/BindBackDto"
        },
        "engine": {
          "enum": [
            "context_graph"
          ],
          "type": "string"
        },
        "error": {
          "type": "string"
        },
        "feedback_token": {
          "type": "string"
        },
        "id": {
          "description": "Caller id echoed from the request.",
          "type": "string"
        },
        "judgment": {
          "additionalProperties": true,
          "type": "object"
        },
        "quote": {
          "type": "string"
        },
        "source_check": {
          "enum": [
            "read",
            "not_read"
          ],
          "type": "string"
        },
        "verification": {
          "$ref": "#/components/schemas/VerificationStampDto"
        }
      },
      "required": [
        "quote",
        "binding",
        "verification",
        "feedback_token"
      ],
      "type": "object"
    },
    "BindBackDto": {
      "properties": {
        "grounded": {
          "description": "True when the quote was found in the resolved source.",
          "type": "boolean"
        },
        "matched_quote": {
          "description": "The matched substring, when grounded verbatim.",
          "type": "string"
        },
        "matched_text": {
          "description": "The best-matching passage found in the source — present even when unbound, so a reviewer sees the closest evidence.",
          "type": "string"
        },
        "method": {
          "description": "How the quote matched: exact/normalized substring, fuzzy passage match, reflowed OCR reading, or unbound.",
          "enum": [
            "exact",
            "normalized",
            "fuzzy",
            "reflowed",
            "unbound"
          ],
          "type": "string"
        },
        "reading": {
          "description": "Derived body reading with page furniture removed; absent for stored text.",
          "enum": [
            "body"
          ],
          "type": "string"
        },
        "rescue": {
          "description": "OCR rescue outcome: attempted=false with code/reason, attempted=true and rescued=false (optionally ambiguous), or rescued=true with transformations, raw dropped lines and retained spans. Unknown or unattempted is never a failed rescue.",
          "oneOf": [
            {
              "properties": {
                "attempted": {
                  "enum": [
                    false
                  ],
                  "type": "boolean"
                },
                "code": {
                  "enum": [
                    "not_ocr",
                    "labels_not_available",
                    "judge_unavailable",
                    "not_prepared",
                    "disabled",
                    "resource_limit"
                  ],
                  "type": "string"
                },
                "reason": {
                  "type": "string"
                }
              },
              "required": [
                "attempted",
                "code",
                "reason"
              ],
              "type": "object"
            },
            {
              "properties": {
                "ambiguous": {
                  "enum": [
                    true
                  ],
                  "type": "boolean"
                },
                "attempted": {
                  "enum": [
                    true
                  ],
                  "type": "boolean"
                },
                "rescued": {
                  "enum": [
                    false
                  ],
                  "type": "boolean"
                }
              },
              "required": [
                "attempted",
                "rescued"
              ],
              "type": "object"
            },
            {
              "properties": {
                "attempted": {
                  "enum": [
                    true
                  ],
                  "type": "boolean"
                },
                "basis": {
                  "enum": [
                    "code",
                    "measured"
                  ],
                  "type": "string"
                },
                "calibrationKey": {
                  "type": "string"
                },
                "decidedAt": {
                  "format": "date-time",
                  "type": "string"
                },
                "droppedLines": {
                  "items": {
                    "type": "string"
                  },
                  "type": "array"
                },
                "model": {
                  "nullable": true,
                  "type": "string"
                },
                "reading": {
                  "description": "Derived matching text; display the raw preview text instead.",
                  "type": "string"
                },
                "rescued": {
                  "enum": [
                    true
                  ],
                  "type": "boolean"
                },
                "retainedSpans": {
                  "items": {
                    "properties": {
                      "fromLine": {
                        "type": "integer"
                      },
                      "page": {
                        "type": "integer"
                      },
                      "toLine": {
                        "type": "integer"
                      }
                    },
                    "required": [
                      "page",
                      "fromLine",
                      "toLine"
                    ],
                    "type": "object"
                  },
                  "type": "array"
                },
                "transformations": {
                  "items": {
                    "properties": {
                      "afterLine": {
                        "type": "integer"
                      },
                      "atLine": {
                        "type": "integer"
                      },
                      "kind": {
                        "enum": [
                          "dehyphenate",
                          "join",
                          "drop"
                        ],
                        "type": "string"
                      },
                      "line": {
                        "type": "string"
                      },
                      "source": {
                        "enum": [
                          "element_label",
                          "repetition",
                          "page_number",
                          "margin_band"
                        ],
                        "type": "string"
                      }
                    },
                    "required": [
                      "kind"
                    ],
                    "type": "object"
                  },
                  "type": "array"
                }
              },
              "required": [
                "attempted",
                "rescued",
                "reading",
                "transformations",
                "droppedLines",
                "retainedSpans",
                "calibrationKey",
                "basis",
                "model",
                "decidedAt"
              ],
              "type": "object"
            }
          ]
        },
        "score": {
          "description": "Similarity of the best match, 0..1.",
          "type": "number"
        }
      },
      "required": [
        "grounded",
        "method"
      ],
      "type": "object"
    },
    "VerificationStampDto": {
      "properties": {
        "band": {
          "enum": [
            "verified",
            "needs_review",
            "unverified"
          ],
          "type": "string"
        },
        "binding_method": {
          "enum": [
            "exact",
            "normalized",
            "fuzzy",
            "reflowed",
            "unbound"
          ],
          "type": "string"
        },
        "confidence": {
          "maximum": 100,
          "minimum": 0,
          "nullable": true,
          "type": "number"
        },
        "grounded": {
          "type": "boolean"
        },
        "layer": {
          "enum": [
            "deterministic",
            "bound",
            "model",
            "unbound"
          ],
          "type": "string"
        },
        "meaning": {
          "enum": [
            "not_checked",
            "faithful",
            "changed",
            "ambiguous"
          ],
          "type": "string"
        },
        "review_reason": {
          "type": "string"
        }
      },
      "required": [
        "layer",
        "band",
        "confidence",
        "grounded",
        "meaning"
      ],
      "type": "object"
    }
  }
}
```
