---
title: Reason
description: Grounded legal Q&A with a hallucination guard that verifies every citation.
order: 1
---

`POST /v1/reason`

Requires a **Pay As You Go** plan — not available on Free.

Retrieves relevant chunks (same pipeline as [`/v1/search`](/docs/api-reference/search), rerank always on), prompts the model to answer using only that context with `[[REF:canonical_id#article_no]]` tokens, then verifies every token against the retrieved set before it reaches you. Invalid refs are stripped, not shown, and counted in `grounding.dropped_unverified_refs` — Dike never fabricates a citation to avoid an empty answer.

```mermaid
flowchart LR
    A[Question] --> B[Retrieve + rerank<br/>same pipeline as /v1/search]
    B --> C[Model answers using<br/>only retrieved context]
    C --> D{Every REF token<br/>in retrieved set?}
    D -->|yes| E[Marker verified<br/>shown as numbered citation]
    D -->|no| F[Stripped, counted in<br/>dropped_unverified_refs]
    E --> G[Response]
    F --> G
```

## Request

```json
{
  "question": "هل يجوز فسخ عقد الإيجار لتأخر المستأجر عن السداد؟",
  "filters": { "jurisdiction": "EG" },
  "top_k": 12,
  "stream": false,
  "language": "ar"
}
```

`filters` accepts the same shape as [`/v1/search`](/docs/api-reference/search). `language` is `"ar"` (default) or `"en"`.

## Response (non-streaming)

```json
{
  "answer": "...نعم، وفقاً للمادة 157 [1] ...",
  "citations": [
    {
      "marker": 1,
      "canonical_id": "eg-leg-1948-131",
      "article_no": "157",
      "citation_string": "المادة 157 من القانون المدني رقم 131 لسنة 1948",
      "snippet": "...",
      "verified": true
    }
  ],
  "grounding": { "retrieved": 12, "used": 4, "dropped_unverified_refs": 0 },
  "took_ms": 3210
}
```

If the answer has zero verified citations and isn't the insufficient-grounding sentinel ("لا أجد سنداً قانونياً كافياً" / an equivalent English refusal), the response still returns normally with `grounding.used: 0`, plus a response header `X-Dike-Grounding: weak` — treat that header as a signal to show the answer with a caveat, not as an error.

## Streaming

`stream: true` switches the response to `text/event-stream`:

```
data: {"token": "..."}
data: {"token": "..."}
event: citations
data: {"citations": [...], "grounding": {...}}
```

Token events are buffered until each `[[REF:...]]` token fully closes, so a REF is never split across a chunk boundary — by the time you see `[1]` in the stream it's already been rewritten from the raw token. The final `citations` event carries the same `citations`/`grounding` shape as the non-streaming response.

## Errors

- `401 unauthorized`
- `403 plan_required` — Free plan; `/v1/reason` needs Pay As You Go
- `422 validation_error`
- `503 upstream_unavailable`
