# DeepSeek API — инструкция для ИИ-агентов

Версия контракта: **1.1.0**. Обновлено: **2026-11-05**.

## Подключение

| Настройка | Значение |
|---|---|
| Адрес сайта | `https://accs.digital` |
| Base URL для OpenAI-совместимого клиента | `https://accs.digital/v1` |
| Модель | `deepseek-v4.1-flash-free` |
| Авторизация | `Authorization: Bearer YOUR_API_KEY` |
| Тело запроса | `Content-Type: application/json`, UTF-8 |
| OpenAPI | <https://accs.digital/openapi.json> |
| Эта инструкция | <https://accs.digital/api.md> |
| Документация в браузере | <https://accs.digital/docs> |

Получите API-ключ у владельца сервиса. Передавайте его через переменную окружения или защищённое хранилище клиента. Примеры ниже используют переменную `DEEPSEEK_API_KEY`. Ключ не требуется помещать в URL, сообщения модели или файлы исходного кода.

Это OpenAI-совместимое **текстовое** API с описанным ниже набором методов. Служебный контекст OpenCode сохраняется и входит в расход. Для каждого обращения передавайте нужную историю сообщений; отдельные запросы не продолжают историю автоматически.

## Быстрый старт

```sh
export DEEPSEEK_API_KEY='YOUR_API_KEY'
curl https://accs.digital/v1/chat/completions \
  -H "Authorization: Bearer $DEEPSEEK_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"model":"deepseek-v4.1-flash-free","messages":[{"role":"user","content":"Ответь одним словом: привет"}],"stream":false}'
```

Читайте текст из `choices[0].message.content`, причину завершения — из `choices[0].finish_reason`, расход — из `usage`, если метрики присутствуют. Сохраняйте `request_id` успешного ответа или заголовок `X-Request-ID` для разбора обращения, включая ошибки.

### Python: клиент OpenAI

```python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://accs.digital/v1",
    api_key=os.environ["DEEPSEEK_API_KEY"],
    timeout=180.0,
    max_retries=0,
)
response = client.chat.completions.create(
    model="deepseek-v4.1-flash-free",
    messages=[
        {"role": "system", "content": "Отвечай кратко."},
        {"role": "user", "content": "Сколько будет 17 умножить на 19?"},
    ],
    max_tokens=512,
)
print(response.choices[0].message.content)
print(response.usage)
```

### PowerShell

```powershell
$headers = @{ Authorization = 'Bearer ' + $env:DEEPSEEK_API_KEY }
$body = @{
    model = 'deepseek-v4.1-flash-free'
    messages = @(@{ role = 'user'; content = 'Reply with exactly OK' })
    stream = $false
} | ConvertTo-Json -Depth 5
$response = Invoke-RestMethod -Method Post `
    -Uri 'https://accs.digital/v1/chat/completions' `
    -Headers $headers -ContentType 'application/json; charset=utf-8' `
    -Body ([Text.Encoding]::UTF8.GetBytes($body)) -TimeoutSec 180
$response.choices[0].message.content
$response.usage
```

## Методы

Все пути ниже относятся к `https://accs.digital`.

| Метод | Путь | Авторизация | Назначение |
|---|---|---|---|
| GET | `/health` | Публичный | Проверка работы адаптера; модель не вызывается |
| GET | `/v1/capabilities` | Публичный | Возможности и ограничения текущей версии API |
| GET | `/v1/models` | Bearer | Список доступных моделей |
| GET | `/v1/models/{model}` | Bearer | Информация о конкретной модели |
| POST | `/v1/chat/completions` | Bearer | Чат в JSON или SSE |
| POST | `/generate` | Bearer | Генерация по строке `prompt` |
| GET | `/v1/key` | Bearer | Статус, лимит и остаток текущего ключа |
| GET | `/v1/usage` | Bearer | Баланс, суммарный расход, дни и последние запросы |

Для модели также принимаются псевдонимы `deepseek-chat` и `opencode/deepseek-v4.1-flash-free`. В ответах используется основной идентификатор. Неизвестная модель в запросе генерации даёт `400`, в методе получения модели — `404`.

### POST /v1/chat/completions

Обязательное поле — `messages`, массив из 1–100 сообщений. Поддержаны роли `system`, `developer`, `user`, `assistant`; требуется хотя бы одно сообщение `user` или `assistant`. Текст переписки не должен быть полностью пустым. Каждое сообщение содержит только `role` и `content`.

`content` принимает строку или массив текстовых частей:

```json
{"role":"user","content":[{"type":"text","text":"Привет"}]}
```

В одном сообщении допускается до 100 текстовых частей; их строки соединяются без дополнительного разделителя. `user` и `assistant` сохраняют роли в переписке, а `system` и `developer` добавляются к штатным системным инструкциям OpenCode. Отдельная иерархия приоритетов OpenAI между `system` и `developer` не реализована.

| Параметр | Тип / диапазон | Поведение |
|---|---|---|
| `model` | Строка | По умолчанию основная модель |
| `messages` | Массив сообщений | Вся необходимая история |
| `stream` | Boolean | По умолчанию `false`; `true` включает SSE |
| `stream_options` | Объект с Boolean `include_usage` | Применяется только при `stream:true`; по умолчанию `include_usage:false` |
| `max_tokens` | Целое 1–32000 | Ограничение генерации |
| `max_completion_tokens` | Целое 1–32000 | Альтернативное имя; вместе с `max_tokens` запрещено |
| `temperature` | Число 0–2 | Параметр генерации модели |
| `top_p` | Число 0–1 | Параметр генерации модели |
| `frequency_penalty` | Число −2–2 | Частотный штраф |
| `presence_penalty` | Число −2–2 | Штраф за присутствие |
| `seed` | Целое 0–4294967295 | Передаётся модели; одинаковый seed не гарантирует идентичный результат |
| `stop` | Строка или 1–4 строки | Каждая непустая, до 256 символов |
| `n` | Целое `1` | Один вариант ответа |
| `user` | Строка до 128 символов | Идентификатор клиента; в сообщения модели не добавляется |

Параметры генерации передаются модели. Неизвестные поля и неподдерживаемые значения отклоняются с `400`, а не молча игнорируются. Изображения, аудио, `tools`, `tool_choice`, `response_format` и другие методы OpenAI в этот контракт не входят.

Пример обычного ответа (числа расхода условные):

```json
{
  "id":"chatcmpl-example",
  "object":"chat.completion",
  "created":1793836800,
  "model":"deepseek-v4.1-flash-free",
  "choices":[{"index":0,"message":{"role":"assistant","content":"323"},"finish_reason":"stop"}],
  "usage":{"prompt_tokens":2110,"completion_tokens":37,"total_tokens":2147,
    "prompt_tokens_details":{"cached_tokens":1920,"cache_write_tokens":0},
    "completion_tokens_details":{"reasoning_tokens":34,"text_tokens":3}},
  "request_id":"example-request-id"
}
```

`finish_reason` отражает завершение модели: обычно `stop`, при достижении лимита вывода — `length`; также возможно `content_filter`. Поле `usage` может отсутствовать, если полные метрики не получены. При малом лимите или остановке по `stop` допустим пустой видимый ответ. Текст reasoning в ответ API не включается.

### Потоковый ответ

```python
stream = client.chat.completions.create(
    model="deepseek-v4.1-flash-free",
    messages=[{"role": "user", "content": "Напиши короткое приветствие"}],
    stream=True,
    stream_options={"include_usage": True},
)
for chunk in stream:
    if chunk.choices:
        print(chunk.choices[0].delta.content or "", end="", flush=True)
    if chunk.usage is not None:
        print("\nUsage:", chunk.usage)
```

На HTTP-уровне это `Content-Type: text/event-stream`. Каждое SSE-событие содержит строку `data: JSON`, а события разделены пустой строкой. Используйте SSE-парсер: сетевой пакет может содержать часть события или несколько событий.

Последовательность: chunk с `delta.role`, chunks с настоящими `delta.content`, завершающий chunk с `finish_reason`, затем `[DONE]`. При `include_usage:true` перед концом приходит отдельный chunk с `choices:[]` и `usage`; если полные метрики неизвестны, `usage` равен `null`. Размер и частота фрагментов не фиксированы и не соответствуют границам токенов. SSE-комментарии, начинающиеся с `:`, являются служебными keep-alive.

Если ошибка возникла до начала потока, обработайте обычный HTTP-статус и JSON ошибки. После начала SSE сервер может отправить `data: {"error":{"message":"...","type":"...","code":502}}`. Такое событие означает неуспешное завершение: не выдавайте частичный текст за полный ответ и не считайте `[DONE]` подтверждением успеха после ошибки.

### POST /generate

Короткий формат принимает `prompt` — непустую строку, а также необязательные `model`, параметры генерации из таблицы и `stream:false`. `n`, `user`, `stream_options` и `stream:true` для этого метода не поддержаны. Для SSE используйте чат.

```sh
curl https://accs.digital/generate \
  -H "Authorization: Bearer $DEEPSEEK_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"prompt":"Reply with exactly OK","max_tokens":128}'
```

Ответ: `{"text":"OK","model":"deepseek-v4.1-flash-free","finish_reason":"stop","usage":{...},"request_id":"..."}`. `usage` присутствует только при наличии полных метрик.

## Баланс и статистика

```sh
curl https://accs.digital/v1/key -H "Authorization: Bearer $DEEPSEEK_API_KEY"
curl https://accs.digital/v1/usage -H "Authorization: Bearer $DEEPSEEK_API_KEY"
```

`GET /v1/key` возвращает сведения только о предъявленном ключе: `id`, `name`, `prefix`, `active`, `unlimited`, `limit_tokens`, `used_tokens`, `remaining_tokens`, `created_at`, `last_used_at`, `object:"api_key"`. Полного ключа в ответе нет. При безлимите `limit_tokens` и `remaining_tokens` равны `null`.

`GET /v1/usage` возвращает:

- `key` — лимит, статус и остаток;
- `summary` — число запросов, успешные, ошибки, ожидающие, неизвестный расход и суммарные токены;
- `daily` — учтённый расход по дням за последние 30 дней (даты UTC);
- `recent` — до 20 последних запросов с временем, статусом, расходом, кодом ошибки и длительностью.

Отключённый ключ может читать свои сведения и статистику; генерация и методы моделей для него закрыты с `403`.

### Как считать токены

`prompt_tokens` включает некешированный вход и чтение/запись кеша. `completion_tokens` включает видимый ответ и reasoning. `total_tokens` — их сумма. Detail-поля являются частями этих чисел: прибавлять кеш или reasoning к `total_tokens` повторно не нужно.

В расход входят также штатные системные инструкции, каталог инструментов OpenCode и переданная история. У запроса с коротким пользовательским текстом входной расход может быть заметно больше самого текста.

Остаток относится к локальному лимиту вашего ключа, заданному владельцем сервиса. Он не показывает неизвестный остаток общей бесплатной квоты OpenCode. Безлимит отменяет только локальный лимит ключа.

Допуск проверяется перед запросом; окончательное потребление известно после ответа. Последний принятый запрос может превысить остаток, после чего новые обращения блокируются до пополнения. Известный расход ошибочных запросов тоже учитывается. При отсутствии метрик расход отмечается неизвестным; не подменяйте его нулём или оценкой по длине текста.

## Ошибки и повторы

```json
{"error":{"message":"Описание ошибки","type":"key_quota_exceeded","code":429}}
```

| HTTP | Тип / причина | Действие агента |
|---|---|---|
| 400 | Невалидные поля, модель или параметры | Исправить запрос |
| 401 | Ключ отсутствует или неверен | Проверить конфигурацию ключа |
| 403 | Ключ отключён | Обратиться к владельцу ключа |
| 404 | Метод или модель не найдены | Проверить путь / идентификатор |
| 413 | Тело запроса больше 256 КиБ | Сократить тело и историю |
| 429 `key_quota_exceeded` | Локальный лимит исчерпан | Требуется пополнение, автоматический повтор бесполезен |
| 429 `gateway_busy` | Слот генерации занят | Уважать `Retry-After`, обычно 2 секунды |
| 429 от провайдера | Внешнее ограничение | Следовать сообщению; не запускать бесконечные повторы |
| 502 / 503 | Ошибка провайдера, адаптера или недоступность | Ограничить число повторов, сохранить `request_id` |
| 504 | Время генерации истекло | Учитывать, что часть токенов уже могла быть потрачена |

В production одновременно выполняется одна генерация. Базовый таймаут — 120 секунд, отмена может занять ещё до 8 секунд. Для клиента рекомендуется таймаут 180 секунд. Автоматический повтор может повторно потратить токены: используйте явную ограниченную стратегию, а не бесконечный цикл.

`GET /health` и список моделей не вызывают модель и не доказывают наличие свободной квоты провайдера. Актуальные возможности доступны в `/v1/capabilities`, а машинная схема — в `/openapi.json`.
