# Verify API

Audit a claim against live web evidence or citations you supply: claim in, four-label verdict out — with span-level quotes, machine-readable reason codes and source authority. Typically takes 5–15 seconds.

**POST** `/v1/verify`

Generally available. A deployment with the endpoint switched off answers 404. Legacy alias: POST https://searchpipe.tech/verify.

## Authorize

Authenticate with your sp- API key in the `Authorization: Bearer sp-YOUR_KEY` header; `X-API-Key: sp-YOUR_KEY` is also accepted. Verification uses the same key and credit balance as [/v1/search](https://searchpipe.tech/docs/search).

## Request

Send `Content-Type: application/json`. Only `claim` is required. Input moderation applies: rejected content returns `400` without a charge.

### Body parameters

**Body**

| Parameter | Type | Description |
| --- | --- | --- |
| `claim` | string · required | The claim (statement or citation) to verify — max 2000 characters. |
| `mode` | string · default auto | Evidence route: paper (DOI/arXiv), web, or auto — a DOI or arXiv signal picks the paper route. |
| `evidence_urls` | string[] · optional | Up to 5 caller-supplied citations to verify; URLs are SSRF-checked. |
| `max_evidence` | integer · default 5 | Maximum number of evidence items to return (1-10). |

### Request example

**curl**

```
curl -X POST https://searchpipe.tech/verify \
  -H "Authorization: Bearer sp-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"claim": "Attention Is All You Need introduced the transformer architecture"}'
```

**Python**

```
import httpx

resp = httpx.post(
    "https://searchpipe.tech/verify",
    headers={"Authorization": "Bearer sp-YOUR_KEY"},
    json={"claim": "Attention Is All You Need introduced the transformer architecture"},
    timeout=60,
)
data = resp.json()
print(data["verdict"], data["reason_code"], data["confidence"])
for ev in data["evidences"]:
    print(ev["per_evidence_verdict"], ev["url"])
```

**JavaScript**

```
const resp = await fetch("https://searchpipe.tech/verify", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sp-YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ claim: "Attention Is All You Need introduced the transformer architecture" }),
});
const data = await resp.json();
console.log(data.verdict, data.reason_code, data.confidence);
for (const ev of data.evidences) console.log(ev.per_evidence_verdict, ev.url);
```

**Go**

```
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"time"
)

func main() {
	payload := []byte(`{"claim":"Attention Is All You Need introduced the transformer architecture"}`)
	req, _ := http.NewRequest("POST", "https://searchpipe.tech/verify", bytes.NewReader(payload))
	req.Header.Set("Authorization", "Bearer sp-YOUR_KEY")
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{Timeout: 60 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	out, _ := io.ReadAll(resp.Body)
	fmt.Println(string(out))
}
```

**Java**

```
import java.net.URI;
import java.net.http.*;
import java.time.Duration;

public class SearchPipeVerify {
    public static void main(String[] args) throws Exception {
        String json = "{\"claim\":\"Attention Is All You Need introduced the transformer architecture\"}";
        HttpClient client = HttpClient.newBuilder()
            .version(HttpClient.Version.HTTP_1_1)
            .connectTimeout(Duration.ofSeconds(10))
            .build();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://searchpipe.tech/verify"))
            .timeout(Duration.ofSeconds(60))
            .header("Authorization", "Bearer sp-YOUR_KEY")
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(json))
            .build();
        HttpResponse<String> resp =
            client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(resp.body());
    }
}
```

**C# (.NET)**

```
using System.Net.Http.Json;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", "sp-YOUR_KEY");

var payload = new
{
    claim = "Attention Is All You Need introduced the transformer architecture",
};

HttpResponseMessage resp = await client.PostAsJsonAsync("https://searchpipe.tech/verify", payload);
resp.EnsureSuccessStatusCode();
Console.WriteLine(await resp.Content.ReadAsStringAsync());
```

## Response

Every verdict carries a machine-readable `reason_code` from a fixed whitelist, and every evidence item carries a verbatim quote span — never a free-form generated explanation. This illustrative response shows the shape; values are examples, not a live verification.

```
{
  "verdict": "supported",
  "confidence": 0.93,
  "reason_code": "quote_span_found",
  "evidences": [
    {
      "url": "https://arxiv.org/abs/1706.03762",
      "title": "Attention Is All You Need",
      "source_tier": "preprint",
      "quote": "We propose a new simple network architecture, the Transformer, based solely on attention mechanisms",
      "span_start": 0,
      "span_end": 103,
      "per_evidence_verdict": "supported",
      "confidence": 0.95,
      "url_health": {
        "status_code": 200,
        "redirected": false,
        "wayback_snapshot": null,
        "fetched_at": "2026-10-30T09:00:00Z"
      }
    }
  ],
  "timing": {"v_prepare": 0.4, "v_evidence": 3.1, "v_judge": 6.2, "v_health": 0.8}
}
```

### Verdict labels

**Four-label verdict scale returned in the verdict field**

| verdict | Meaning |
| --- | --- |
| `supported` | Fetched evidence whose text explicitly supports the claim. |
| `partial` | The evidence supports part of the claim, or the support is weak. |
| `unsupported` | Reachable evidence does not support the claim — catches misattributed or hallucinated citations. |
| `inconclusive` | No verdict possible: fetch failures, paywalls or insufficient checkable evidence. A valid deliverable, billed like any other verdict. |

### reason_code whitelist

**Machine-readable reasons returned in the reason_code field**

| reason_code | Meaning |
| --- | --- |
| `doi_match` | The claim resolved to a DOI that points to a real paper. |
| `title_match` | The claim matched a known paper title (fuzzy). |
| `quote_span_found` | A verbatim span supporting the claim was located in a fetched source. |
| `no_supporting_evidence` | Sources were reachable but none of them supports the claim. |
| `fetch_failed` | Candidate sources could not be fetched. |
| `paywall` | Candidate sources sit behind a paywall. |
| `low_authority` | Only low-authority sources were available, so confidence stays low. |
| `conflicting_evidence` | The evidence points in more than one direction. |

### Response fields

**200 response body**

| Field | Type | Description |
| --- | --- | --- |
| `verdict` | string | One of supported, partial, unsupported, inconclusive (table above). |
| `confidence` | number | 0-1 confidence in the verdict. |
| `reason_code` | string | Machine-readable reason from the whitelist above — template phrases, never free-form text. |
| `evidences` | array | Evidence items, each with url, title, source_tier (official/press/academic/preprint/community/unknown), quote, span_start, span_end, per_evidence_verdict, confidence and url_health (status_code, redirected, wayback_snapshot, fetched_at). |
| `timing` | object | Per-stage wall time in seconds (v_prepare, v_evidence, v_judge, v_health). |

## Verify a batch of claims

**POST**`/v1/verify/batch`

Check up to 20 claims in one synchronous request and handle each result independently. Partial failures do not fail the whole batch.

**Batch body**

| Parameter | Description |
| --- | --- |
| `claims` | Required array of 1–20 statements; each is limited to 2,000 characters. |
| `mode` | auto (default), paper, or web; applied to the entire batch. |
| `max_evidence` | 1–10 evidence items per claim; default 5. This endpoint does not accept evidence_urls. |

**Batch response fields**

| Field | Meaning |
| --- | --- |
| `results[]` | Matches the order of claims. Each item has the single-claim response shape, or null when that item fails. |
| `failed[]` | Each failure includes index (zero-based position in claims) and error. Partial failures do not fail the whole batch. |

```
curl -X POST "https://searchpipe.tech/v1/verify/batch" \
  -H "Authorization: Bearer sp-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "claims": [
    "FastAPI is a Python web framework.",
    "Python was created by Guido van Rossum."
  ],
  "mode": "web",
  "max_evidence": 5
}'
```

The batch is charged before execution. Failed items are refunded; completed inconclusive verdicts are charged. The batch is a synchronous REST endpoint, not a background job — there is no separate MCP batch tool.

## Billing and error handling

- **1 credit per claim.** An `inconclusive` verdict is a completed verification and is charged; overall pipeline failures return `503` and are refunded automatically.
- Input moderation rejections return `400` without a charge.
- Verdicts are not cached — a verdict depends on the live state of the cited pages.
- A deployment with the endpoint switched off answers `404`.

## Related pages

[Verification API product page](https://searchpipe.tech/verify-api)[Search API reference (evidence and answer audits)](https://searchpipe.tech/docs/search)[Agent setup with searchpipe_verify](https://searchpipe.tech/agents)[Docs home](https://searchpipe.tech/docs)
