# Tab

> Inline completions for any editor, through an OpenAI-compatible endpoint.

Source: https://docs.coline.app/api/tab

Tab suggests what you'll write next and shows it as ghost text at the cursor. Press **Tab** to accept it, **Escape** to dismiss it, or keep typing to ignore it. It's built into Coline's editors, and the same completions are available to your own editors through the API.

## In Coline

Tab works in Notes, Docs, the Messages composer, task descriptions and fields, calendar event descriptions, and the Code editor. Suggestions use the text around the cursor, the document's title, and your local date. Turn it off in your account settings if you don't want it.

## API

```text
POST https://coline.app/api/v1/tab/chat/completions
```

The endpoint follows the OpenAI chat completions format, so OpenAI-compatible clients work with it. Coline-specific context goes in `tab_context`. It needs an [API key](/authentication/api-keys) or OAuth token with the `ai.invoke` scope, and is billed to the workspace's API credits.

### Models

`GET /api/v1/tab/models` lists models and prices. It needs no auth.

| Model              | Surfaces                                                | Input, per million tokens | Output, per million tokens |
| ------------------ | ------------------------------------------------------- | ------------------------- | -------------------------- |
| `tab-v1` (default) | `any`, `notes`, `docs`, `messages`, `tasks`, `calendar` | $0.20                     | $0.50                      |
| `tab-1-code`       | `code`                                                  | $0.08                     | $0.28                      |

### Request

```bash
curl https://coline.app/api/v1/tab/chat/completions \
  -H "Authorization: Bearer col_ws_..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "tab-v1",
    "stream": true,
    "max_completion_tokens": 100,
    "tab_context": {
      "surface": "docs",
      "entity_id": "doc_123",
      "document_type": "markdown",
      "document_title": "Q3 planning",
      "active_text_before_cursor": "Our goals for the quarter are ",
      "active_text_after_cursor": ""
    }
  }'
```

| Field                   |             |                                                                                              |
| ----------------------- | ----------- | -------------------------------------------------------------------------------------------- |
| `model`                 | Optional    | `tab-v1` by default. Use `tab-1-code` with the `code` surface                                |
| `stream`                | Optional    | `true` streams Server-Sent Events. Recommended                                               |
| `max_completion_tokens` | Optional    | 1 to 500. Defaults to 500. `max_tokens` also works                                           |
| `temperature`, `top_p`  | Optional    | Temperature defaults to 0.2                                                                  |
| `messages`              | Optional    | If you don't send `tab_context`, the last user message is used as the text before the cursor |
| `tab_context`           | Recommended | See below                                                                                    |

`tab_context`:

| Field                          |          |                                                                                                               |
| ------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------- |
| `surface`                      | Required | `notes`, `docs`, `messages`, `tasks`, `calendar`, `code`, or any short name for your editor (`any` works too) |
| `active_text_before_cursor`    | Required | Up to 16,000 characters                                                                                       |
| `active_text_after_cursor`     | Optional | Up to 16,000 characters                                                                                       |
| `surrounding_context`          | Optional | Other useful context, up to 32,000 characters                                                                 |
| `document_type`                | Optional | `markdown` (default) or `plaintext`                                                                           |
| `entity_id`                    | Optional | An ID for the document or file, for caching and analytics                                                     |
| `workspace_slug`               | Optional | Defaults to the API key's workspace                                                                           |
| `document_title`, `note_title` | Optional | Title of the document being edited                                                                            |
| `block_kind`                   | Optional | The kind of block at the cursor, such as `paragraph` or `bulleted-list`                                       |
| `code_language`, `file_path`   | Code     | For the `code` surface                                                                                        |
| `completion_mode`              | Code     | `line` for one line, `block` for several                                                                      |
| `client_local_date`            | Optional | The person's local date, such as `2026-10-12 Mon`, so relative dates come out right                           |
| `taskboard_file_id`            | Tasks    | Required when `surface` is `tasks`                                                                            |

### Response

Streaming responses are standard chat completion chunks, ending with `[DONE]`:

```text
data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":" shipping"},"finish_reason":null}]}

data: {"object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":" the new"},"finish_reason":null}]}

data: [DONE]
```

Without streaming you get one `chat.completion` object with the text in `choices[0].message.content` and token counts in `usage`.

Insert the text at the cursor as ghost text. Tab doesn't repeat what's already after the cursor.

## Credits

Each call reserves the most it could cost from the workspace's API credit balance, then refunds the difference when it finishes. If the balance is too low, the call fails with `402 INSUFFICIENT_CREDITS`. Add credits in the [developer console](https://coline.app/developers/console) under **Credits**; the minimum purchase is $5. The console's **Tab playground** lets you try completions first.
