# Chats

Ask questions about a fixed set of documents and papers, and get answers with page-level citations.

## When to use

- The caller already knows which sources matter
- You want a conversation with follow-ups
- You need to stream an answer into a UI

## When not to use

- You do not know which papers matter yet → searches
- One-shot structured fields across many PDFs → extractions

## Endpoints

| Method | Path | Scope | Credits | Description |
|---|---|---|---|---|
| POST | `/v1/chats` | `chats:write` | 0 | Create, scoped to documents/papers |
| GET | `/v1/chats/{id}` | `chats:read` | 0 | Retrieve |
| POST | `/v1/chats/{id}/messages` | `chats:write` | 2 / 6 / 20 by depth | Ask a question; supports `stream` |
| GET | `/v1/chats/{id}/messages` | `chats:read` | 0 | List turns |

## Parameters — create a chat

| Parameter | Type | Required | Description |
|---|---|---|---|
| `document_ids` | string[] | one of | Your uploaded documents |
| `paper_ids` | string[] | one of | Corpus papers |
| `depth` | enum | no | Default for messages in this chat |
| `language` | string | no | Answer language |

## Parameters — send a message

| Parameter | Type | Required | Description |
|---|---|---|---|
| `content` | string | yes | The question |
| `stream` | boolean | no | SSE streaming, default `false` |
| `depth` | enum | no | Overrides the chat default |
| `answer_format` | enum | no | `bulleted`, `paragraph` |

## Streaming

Set `"stream": true` and the response is `text/event-stream`. Events arrive in a fixed order:
`message.delta` repeatedly, then `citation.added` as sources resolve, then one `message.completed`.

```bash
curl -N https://api.scispace.com/v1/chats/chat_1r8eaidwoq/messages \
  -H "Authorization: Bearer $SCISPACE_API_KEY" \
  -H "SciSpace-Version: 2026-08-01" \
  -H "Content-Type: application/json" \
  -d '{"content":"How many layers does the encoder use?","stream":true}'
```

```text
event: message.delta
data: {"id":"msg_k7hcnivfll","delta":"The encoder and decoder each use "}

event: message.delta
data: {"id":"msg_k7hcnivfll","delta":"six identical layers [1]."}

event: citation.added
data: {"index":1,"quote":"The encoder is composed of a stack of N = 6 identical layers.","source":{"type":"document","id":"doc_8ba2f01c47"},"locations":[{"page":7,"bbox":{"x":0.252,"y":0.426,"width":0.495,"height":0.041}}]}

event: message.completed
data: {"id":"msg_k7hcnivfll","credits_cost":2,"unsourced_claim_count":0}
```

Citations arrive **after** the text that references them, so render `[n]` markers as inert until the
matching `citation.added` lands. The SDKs expose the same stream as an iterator:

```python
with client.chats.messages.stream(
    chat_id="chat_1r8eaidwoq",
    content="How many layers does the encoder use?",
) as stream:
    for event in stream:
        if event.type == "message.delta":
            print(event.delta, end="", flush=True)
        elif event.type == "citation.added":
            print(f"\n[{event.index}] p.{event.locations[0].page}")
    message = stream.get_final_message()
```

```typescript
const stream = client.chats.messages.stream({
  chat_id: "chat_1r8eaidwoq",
  content: "How many layers does the encoder use?",
});

for await (const event of stream) {
  if (event.type === "message.delta") process.stdout.write(event.delta);
  else if (event.type === "citation.added") console.log(`\n[${event.index}]`);
}

const message = await stream.finalMessage();
```

> [!warning] A dropped connection still costs credits
> The message is billed once generation starts. Reconnecting does not resume the stream — retrieve
> the message by id instead.

## Response

```json
{
  "object": "message",
  "id": "msg_k7hcnivfll",
  "chat_id": "chat_1r8eaidwoq",
  "role": "assistant",
  "content": "The encoder and decoder each use six identical layers [1], and the model reaches 28.4 BLEU on WMT 2014 English-to-German [2].",
  "citations": [
    {
      "index": 1,
      "quote": "The encoder is composed of a stack of N = 6 identical layers.",
      "source": {
        "type": "document",
        "id": "doc_8ba2f01c47",
        "title": "Attention is all you need.pdf"
      },
      "locations": [
        {
          "page": 7,
          "bbox": {
            "x": 0.252,
            "y": 0.426,
            "width": 0.495,
            "height": 0.041
          }
        }
      ]
    },
    {
      "index": 2,
      "quote": "Our model achieves 28.4 BLEU on the WMT 2014 English-to-German translation task.",
      "source": {
        "type": "document",
        "id": "doc_8ba2f01c47",
        "title": "Attention is all you need.pdf"
      },
      "locations": [
        {
          "page": 8,
          "bbox": {
            "x": 0.118,
            "y": 0.204,
            "width": 0.63,
            "height": 0.038
          }
        }
      ]
    }
  ],
  "unsourced_claim_count": 0,
  "credits_cost": 2,
  "created_at": "2026-08-11T09:31:07Z"
}
```

| Field | Type | Description |
|---|---|---|
| `role` | enum | `user` or `assistant` |
| `content` | string | The reply, carrying `[n]` markers keyed to `citations[].index` |
| `citations[].quote` | string | The source span, verbatim. Use it to sanity-check the claim |
| `citations[].source.type` | enum | `document` for your uploads, `paper` for corpus items |
| `citations[].locations[].page` | integer | **1-indexed** |
| `citations[].locations[].bbox` | object | `x`, `y`, `width`, `height` as fractions of the page, origin top-left |
| `unsourced_claim_count` | integer | Sentences with no citation. Surface it rather than hiding it |

A citation can carry more than one location when the claim spans a page break. Render every one.

> [!info] bbox values are fractions, not pixels
> Multiply by your rendered page size. citation-highlights shows the overlay maths against this
> exact citation.

## Errors

| Status | `code` | When |
|---|---|---|
| 400 | `no_sources` | neither `document_ids` nor `paper_ids` given |
| 409 | `document_not_ready` | a document is still parsing |
| 413 | `too_many_sources` | more than 50 documents and papers combined |

## Related

chat · message · citation · grounded-answers
