SafeLaw API

Юридические ответы по законодательству Узбекистана в вашем приложении. В каждом ответе — не только текст, но и ссылки на нормы: статья, её текст и ссылка на lex.uz, сверенные с базой актов.

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

  1. Получите ключ в кабинете: Настройки → API.
  2. Пополните кошелёк — с него списываются запросы (все ключи тратят общий баланс).
  3. Отправьте запрос на https://api.safelaw.ai/v1/chat с ключом в заголовке.
curl https://api.safelaw.ai/v1/chat \
  -H "Authorization: Bearer sf_live_ВАШ_КЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{
    "question": "Какой срок исковой давности по трудовым спорам?",
    "model": "safelaw-standard"
  }'

Единственный адрес API — https://api.safelaw.ai/v1/…. Пути вида safelaw.ai/api/… — это внутренние роуты сайта под сессионную авторизацию, они вернут 401 на ключ sf_live_…. Машиночитаемая спецификация (OpenAPI 3.0): api.safelaw.ai/v1/openapi.json.

Ключи и аутентификация

Ключ передаётся в заголовке Authorization: Bearer sf_live_…. Создаётся в кабинете и показывается один раз — храните его надёжно.

POST /v1/chat

Параметры тела (JSON):

ПолеОбяз.Описание
questionдаВопрос, до 8000 символов
modelнетsafelaw-standard (по умолч.) или safelaw-pro (сложнее/дороже)
jurisdictionнетПока только UZ
attachmentsнетФайлы для анализа: массив { filename, content }, где content — файл в base64. До 3 файлов: документы (pdf, docx, doc, txt) и до 1 изображения (jpg, png, webp). Документы извлекаются в текст, фото читает модель.

Ответ (200):

{
  "id": "req_c6d549149002a83b8d5118e5",
  "object": "chat.completion",
  "created": 1786555918,
  "model": "safelaw-standard",
  "answer": "В Узбекистане сроки обращения в суд по трудовым спорам установлены ст. 560 ТК РУз...",
  "citations": [
    {
      "act": "Трудовой кодекс Республики Узбекистан",
      "article": "560",
      "text": "Для обращения в суд за рассмотрением индивидуального трудового спора...",
      "url": "https://lex.uz/acts/6257291",
      "verified": true
    }
  ],
  "usage": { "input_tokens": 36819, "output_tokens": 446, "total_tokens": 37265 }
}

Файлы: анализ документов и генерация

Приложите документы или фото в attachments — их разберут вместе с вопросом (документ извлекается в текст, фото читает модель). А если попросить составить документ (иск, договор, заявление) — готовый текст вернётся в поле document.

# Анализ документа (или фото): приложите файл в attachments (base64)
curl https://api.safelaw.ai/v1/chat \
  -H "Authorization: Bearer sf_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "question": "Проанализируй этот договор: какие риски?",
    "attachments": [
      { "filename": "contract.pdf", "content": "<файл в base64>" }
    ]
  }'

# Если попросить составить документ — готовый текст придёт в поле document:
# { "answer": "...", "document": { "title": "ИСКОВОЕ ЗАЯВЛЕНИЕ", "content": "..." } }

GET /v1/usage

Остаток кошелька и лимиты. Тот же заголовок авторизации.

curl https://api.safelaw.ai/v1/usage -H "Authorization: Bearer sf_live_..."

Оплата

Каждый запрос списывает деньги прямо с кошелька аккаунта — отдельно покупать токены на ключ не нужно, все ключи тратят общий баланс. Тариф по токенам: вход — $4 за 1M, выход — $20 за 1M (считаются токены запроса и ответа). Точная стоимость каждого запроса приходит в usage.cost_uzs (в сумах), остаток — в заголовке X-Wallet-Balance-Uzs. Когда средства заканчиваются — ответ 402 с details.reason = "no_funds". Пополнение — в кабинете.

Лимиты и заголовки

60 запросов в минуту на боевой ключ (10 на отладочный). В каждом ответе есть заголовки, чтобы заранее видеть приближение к пределу:

ЗаголовокЗначение
X-Request-IdИдентификатор запроса — присылайте в поддержку
X-Wallet-Balance-UzsОстаток на кошельке в сумах
X-Quota-Remaining-TokensОстаток в пересчёте на токены
X-RateLimit-Limit-RequestsЛимит запросов в минуту
X-RateLimit-Remaining-RequestsСколько осталось в текущем окне
Retry-AfterЧерез сколько секунд повторить (при 429)

Повторы без двойного списания

При обрыве связи неизвестно, выполнился ли запрос. Передайте заголовок Idempotency-Key — повтор с тем же значением вернёт сохранённый ответ и не спишет деньги второй раз.

Ошибки

Формат один и тот же всегда: type — категория (ветвите логику по ней), code — точная причина, message/message_en — что делать, param — поле при ошибке ввода, request_id — для поддержки.

{
  "error": {
    "type": "insufficient_quota",
    "code": "no_funds",
    "message": "На кошельке нет средств. Пополните кошелёк.",
    "message_en": "Wallet balance is empty. Top up the wallet in the dashboard.",
    "request_id": "req_1eb7a09fc0db4787",
    "doc_url": "https://safelaw.ai/developers"
  }
}
HTTPtypeЧто делать
401invalid_api_keyКлюч не передан или неверного формата — проверьте заголовок
401revoked_api_keyКлюч отозван — создайте новый в кабинете
402insufficient_quotaНет средств (code=no_funds) или месячный предел (monthly_cap_reached)
429rate_limit_exceededСлишком часто — повторите через секунды из заголовка Retry-After
400invalid_requestОшибка в теле — поле в error.param
400context_too_largeВопрос длиннее 8000 символов — сократите
422unsupported_jurisdictionПоддерживается только UZ
503service_unavailableСервис временно недоступен — повтор с задержкой
504timeoutНе уложились по времени — повторите

Ошибки поставщика модели наружу не протекают — вы получаете либо ответ, либо честную ошибку с понятным действием.

Примеры кода

Python

import requests

r = requests.post(
    "https://api.safelaw.ai/v1/chat",
    headers={"Authorization": "Bearer sf_live_..."},
    json={"question": "Какой срок исковой давности по трудовым спорам?"},
    timeout=120,
)

if r.status_code == 402:
    d = r.json()["error"]["details"]
    raise SystemExit("Нет средств" if d["reason"] == "no_funds" else "Месячный предел")
r.raise_for_status()

data = r.json()
print(data["answer"])
for c in data["citations"]:
    print(f'{c["act"]} ст. {c["article"]} -> {c["url"]}  (сверено: {c["verified"]})')
print("Токенов:", data["usage"]["total_tokens"])

Node.js

const res = await fetch("https://api.safelaw.ai/v1/chat", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sf_live_...",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ question: "Какой срок исковой давности по трудовым спорам?" }),
});

if (!res.ok) {
  const { error } = await res.json();
  throw new Error(`${error.type}/${error.code}: ${error.message}`);
}
const data = await res.json();
console.log(data.answer);
data.citations.forEach((c) => console.log(c.act, "ст.", c.article, c.url));

Ключи создаются в кабинете, в разделе «API».

Получить ключ

Технические вопросы по API: api@safelaw.ai. Подключение API для компании, договор и счёт: sales@safelaw.ai.