APIDOCINSPECT

Готовые сценарии

Готовый копируемый код под пять реальных сценариев — импорт из Китая, ЭДО, чертежи, приемка поставки, разбор архива договоров.

Сценарии ниже разобраны на странице кейсов с измеренными результатами на реальных документах — здесь тот же материал в формате «скопировал — запустил». Все примеры используют один эндпоинт /v1/process; принципы проектирования схемы — в «output_schema».

То же самое без кода

Первые сценарии целиком повторяются в кабинете мышкой: тип документа → колонки → файл → Excel, без единой строки кода — см. «Кабинет и обработка без кода».

Упаковочный лист из Китая → Excel с переводом

Задача. Поставщик присылает packing list на китайском, а нужен русский Excel: реквизиты отгрузки, таблица позиций с наименованиями по-русски и весами — чтобы свести с заказом и отдать на склад.

Три поля отвечают за весь сценарий: language=zh (без него иероглифы на скане не распознаются), translate={"to":"ru"} — перевод строковых значений result после извлечения, и format=xlsx при заборе результата. Перевод требует непустую output_schema, иначе TRANSLATE_REQUIRES_SCHEMA (422).

TASK=$(curl -s -X POST https://api.docinspect.ru/v1/process \
  -H "X-API-Key: $API_KEY" \
  -F "file=@packing_list.pdf" \
  -F "document_type=packing_list" \
  -F "language=zh" \
  -F 'translate={"to":"ru"}' \
  -F "async=true" \
  -F 'output_schema={
        "type": "object",
        "properties": {
          "number": {"type": "string", "title": "Номер"},
          "shipper": {"type": "string", "title": "Отправитель"},
          "consignee": {"type": "string", "title": "Получатель"},
          "gross_weight_total": {"type": "number", "title": "Брутто, кг"},
          "items": {
            "type": "array",
            "title": "Позиции",
            "items": {
              "type": "object",
              "properties": {
                "article": {"type": "string", "title": "Артикул"},
                "name": {"type": "string", "title": "Наименование"},
                "quantity": {"type": "number", "title": "Количество"},
                "unit": {"type": "string", "title": "Единица"},
                "net_weight": {"type": "number", "title": "Нетто, кг"}
              }
            }
          }
        }
      }' | jq -r .task_id)

async=true здесь не формальность: скан упаковочного листа проходит OCR и перевод, а внешний прокси рвет синхронное соединение на 300 секундах. Поллинг — тем же ключом, пока status не станет done:

curl -s https://api.docinspect.ru/v1/process/$TASK -H "X-API-Key: $API_KEY" | jq .status
# processing → done

curl -H "X-API-Key: $API_KEY" \
  "https://api.docinspect.ru/v1/process/$TASK?format=xlsx" -o packing_list.xlsx

Пока status=processing, ?format=xlsx вернет тот же JSON, а не файл — дожидайтесь done. JSON того же результата:

{
  "result": {
    "shipper": "深圳市华强电子有限公司",
    "items": [{ "name": "不锈钢法兰 DN50 PN16", "quantity": 10, "unit": "个" }]
  },
  "translated": {
    "to": "ru",
    "result": {
      "shipper": "Шэньчжэньская компания «Хуацян электроникс»",
      "items": [{ "name": "Фланец из нержавеющей стали DN50 PN16", "quantity": 10, "unit": "шт." }]
    }
  },
  "usage": { "pages": 2, "sheets": 2, "translation_tokens": 412 }
}

title каждого свойства схемы становится заголовком колонки в Excel — поэтому в примере они заполнены по-русски. Механика перевода и устройство листов файла — в «/v1/process» → «Перевод и Excel»; термины (единицы измерения, типы упаковки, Инкотермс) закрывает глоссарий без обращения к модели.

Входящая первичка из ЭДО

Задача. Счета, акты и УПД приходят потоком от разных контрагентов, в разных шаблонах (где-то ИНН продавца в шапке, где-то — в таблице реквизитов). Нужно разложить по единым полям и сверить суммы, прежде чем документ уйдет в учетную систему.

curl -X POST https://api.docinspect.ru/v1/process \
  -H "X-API-Key: $API_KEY" \
  -F "file=@invoice-0148.pdf" \
  -F "prompt=Извлеки реквизиты сторон, позиции и суммы счета. Поставщика и покупателя определяй по подписям «Поставщик»/«Покупатель», а не по порядку появления в документе" \
  -F 'output_schema={
        "type": "object",
        "properties": {
          "number": {"type": "string"},
          "supplier": {"type": "object"},
          "customer": {"type": "object"},
          "items": {"type": "array"},
          "total_amount": {"type": "number"}
        }
      }'
{
  "result": {
    "number": "0148",
    "supplier": { "name": "ООО «Балтмонтаж»", "inn": "7801234565", "kpp": "780101001" },
    "customer": { "name": "ООО «Невский Провиант»", "inn": "7810998874", "kpp": "781001001" },
    "items": [{ "service_type": "Термоусадочная пленка", "quantity": 40, "amount": 128000.0 }],
    "total_amount": 153600.0
  },
  "usage": { "pages": 1, "sheets": 1 },
  "metadata": { "extraction_status": "full", "cached": false, "…": "…" },
  "warnings": []
}

Расхождение итога со строками не нужно ловить самому: если сумма документа не сходится с позициями, в ответе появится warning totals_mismatch (см. «Ошибки»).

Когда промпт можно убрать

Если поток однотипный и роли сторон в бланках устойчивы, тот же вызов работает и без prompt — одной output_schema. Это короче по времени обработки; на нестандартных бланках промпт с явным правилом «как отличить поставщика от покупателя» надежнее.

Конвейер проверки чертежей

Задача. Альбом чертежей по ГОСТ 2.106 нужно превратить в таблицу BOM (обозначения, наименования, количества) и сверить позиции с реестром снабжения, не сохраняя сам реестр на стороне API.

curl -X POST https://api.docinspect.ru/v1/process \
  -H "X-API-Key: $API_KEY" \
  -F "file=@gearbox.pdf" \
  -F "prompt=Извлеки обозначение, масштаб и спецификацию (BOM) чертежа" \
  -F 'include=["tables","fields"]' \
  -F 'output_schema={
        "type": "object",
        "properties": {
          "designation": {"type": "string"},
          "scale": {"type": "string"},
          "specification": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "position": {"type": "string"},
                "designation": {"type": "string"},
                "name": {"type": "string"},
                "quantity": {"type": "integer"}
              }
            }
          }
        }
      }'

include: ["tables", "fields"] — то, ради чего чертежи вообще идут в API: tables возвращает таблицу спецификации, собранную по линиям сетки векторного слоя, а fields — provenance: страницу и координаты, где найдено каждое значение. Обе секции доступны только для PDF.

{
  "result": {
    "designation": "МПСТ.01.00.00СБ",
    "scale": "1:2",
    "specification": [
      { "position": "1", "designation": "МПСТ.01.01.00СБ", "name": "Крышка смотрового отверстия", "quantity": 1 },
      { "position": "2", "designation": "МПСТ.01.02.00СБ", "name": "Тихоходный вал", "quantity": 1 }
    ]
  },
  "tables": [{ "pages": [0], "markdown": "| Поз. | Обозначение | Наименование | Кол. |\n…" }],
  "fields": [{ "name": "designation", "value": "МПСТ.01.00.00СБ", "page": 1, "level": "L1", "bbox": [612, 780, 742, 796] }],
  "usage": { "pages": 8, "sheets": 1 }
}

Лист формата А1 — это восемь тарифицируемых страниц при одном физическом листе; usage показывает оба числа, чтобы счет не выглядел ошибкой (см. «Квоты и биллинг»).

Там, где спецификация нарисована кривыми, а не набрана текстом, подключается OCR по вырезанной области листа — на контракт ответа это не влияет.

Приемка поставки

Задача. Груз приходит с накладной ЦМР/ТТН и упаковочным листом — до подписания приемки нужно свести вес нетто и брутто, количество мест и позиции с заказом, а позиции еще и проверить по реестру снабжения.

curl -X POST https://api.docinspect.ru/v1/process \
  -H "X-API-Key: $API_KEY" \
  -F "file=@cmr-4471.pdf" \
  -F "prompt=Извлеки стороны, груз и вес по накладной ЦМР/ТТН" \
  -F 'output_schema={
        "type": "object",
        "properties": {
          "cmr_number": {"type": "string"},
          "sender": {"type": "object"},
          "consignee": {"type": "object"},
          "cargo": {"type": "object"},
          "gross_weight_kg": {"type": "number"},
          "net_weight_kg": {"type": "number"}
        }
      }'
{
  "result": {
    "cmr_number": "4471/1",
    "sender": { "name": "ООО «Стальпром»", "country": "RU" },
    "consignee": { "name": "ООО «Балтийский склад»", "country": "RU" },
    "cargo": { "packages_count": 18, "description": "Металлопрокат, паллеты" },
    "gross_weight_kg": 412,
    "net_weight_kg": 380
  },
  "usage": { "pages": 1, "sheets": 1 },
  "warnings": []
}

Инвариант «нетто ≤ брутто» проверяется на сервере: если в документе веса перепутаны, ответ придет с предупреждением, а не с тихо принятыми значениями:

{
  "warnings": [
    {
      "code": "weight_invariant_violation",
      "field": "net_weight_kg",
      "severity": "high",
      "message": "net_weight_kg > gross_weight_kg"
    }
  ]
}

Позиции упаковочного листа сверяются с реестром снабжения тем же вызовом — match и вторая file-part registry, отдельного запроса не нужно:

curl -X POST https://api.docinspect.ru/v1/process \
  -H "X-API-Key: $API_KEY" \
  -F "file=@packing-list.pdf" \
  -F 'output_schema={"type":"object","properties":{"items":{"type":"array",
      "items":{"type":"object","properties":{"article":{"type":"string"},
      "quantity":{"type":"number"}}}}}}' \
  -F 'match={"key_column":"ARTCL","values_from":"items[].article"}' \
  -F "registry=@registry.csv"
{
  "result": { "items": [{ "article": "МПСТ.01.01.00СБ", "quantity": 1 }] },
  "match": {
    "found": 1,
    "missing_in_registry": ["МПСТ.01.02.00СБ"],
    "unmatched_registry": [],
    "coverage": 0.5,
    "registry_rows": 240,
    "key_column": "ARTCL",
    "values_field": "items[].article"
  }
}

Реестр обрабатывается в памяти запроса и не сохраняется. Если по правилам компании он не должен покидать ее контур вовсе — та же сверка доступна SDK docai-match на вашей стороне.

Подшивка документов поставки

Задача. Экспедитор прислал одним PDF всё, что ехало с грузом: транзитную декларацию, два электронных счёта, CMR, инвойсы и упаковочные листы — 13 страниц сканов на турецком, английском и русском. Нужно разложить их по документам и из каждого вытащить своё.

split: {"mode": "auto"} находит границы по титулам страниц (транзит, e-Fatura, CMR, инвойс, упаковочный лист) и маркерам продолжения, каждой секции ставит doc_type с номером. Со схемой из каждой секции сразу извлекаются данные; language=tr подсказывает OCR и переводчику турецкий, translate={"to":"ru"} переводит значения. Схема подшивки — общая: тип, номер, дата, стороны, итог, вес, места и строки.

curl -X POST https://api.docinspect.ru/v1/process \
  -H "X-API-Key: $API_KEY" \
  -F "file=@shipment_pack.pdf" \
  -F "language=tr" \
  -F 'split={"mode":"auto"}' \
  -F 'translate={"to":"ru"}' \
  -F 'output_schema={
        "type": "object",
        "properties": {
          "number": {"type": "string", "title": "Номер"},
          "date": {"type": "string", "format": "date", "title": "Дата"},
          "issuer": {"type": "string", "title": "Отправитель / продавец"},
          "recipient": {"type": "string", "title": "Получатель / покупатель"},
          "total": {"type": "number", "title": "Итого"},
          "currency": {"type": "string", "title": "Валюта"},
          "gross_weight_kg": {"type": "number", "title": "Брутто, кг"},
          "packages_total": {"type": "number", "title": "Мест"}
        }
      }'
{
  "result": null,
  "documents": [
    { "index": 1, "pages": [1, 2], "doc_type": "Транзитная декларация 24TR34120001542615", "result": { "packages_total": 5, "gross_weight_kg": 3870 }, "translated": { "to": "ru", "result": { "…": "…" } } },
    { "index": 2, "pages": [3, 3], "doc_type": "Транзитная декларация 24LR3412003297037", "result": { "…": "…" } },
    { "index": 3, "pages": [4, 4], "doc_type": "Инвойс RFF2024000000034", "result": { "total": 77882, "currency": "EUR" } },
    { "index": 5, "pages": [6, 6], "doc_type": "CMR", "result": { "…": "…" } },
    { "index": 7, "pages": [8, 9], "doc_type": "Упаковочный лист", "result": { "…": "…" } }
  ],
  "usage": { "pages": 13, "sheets": 13 }
}

Дальше каждая секция идёт своей дорогой: инвойс — в сверку с заказом, упаковочный лист — на склад, декларация — брокеру. Если нужна не общая, а своя схема на каждый тип, режьте без схемы (split без output_schema — только границы и doc_type, без обращения к модели) и отправляйте секции вторым вызовом с рецептом под тип: сплиттер отдаёт pdf_base64 каждой секции при return_files: true.

Разбор архива договоров

Задача. Сшивка из договора и приложений в одном PDF на десятки-сотни страниц — архив нужно разложить на отдельные документы и извлечь условия, сроки и суммы по каждому, не упираясь в тайм-аут внешнего прокси.

Раньше это были два вызова — нарезка, затем извлечение по каждой секции. Теперь это один запрос: split вместе с output_schema означает «разбей и извлеки из каждого».

curl -X POST https://api.docinspect.ru/v1/process \
  -H "X-API-Key: $API_KEY" \
  -F "file=@lease-archive.pdf" \
  -F "async=true" \
  -F 'split={"mode":"auto"}' \
  -F "prompt=Извлеки стороны, срок действия и сумму договора" \
  -F 'output_schema={
        "type": "object",
        "properties": {
          "title": {"type": "string"},
          "parties": {"type": "array", "items": {"type": "object"}},
          "valid_until": {"type": "string", "description": "YYYY-MM-DD"},
          "total_amount": {"type": "number"}
        }
      }'
{ "task_id": "a3f9c1e0", "poll_url": "/v1/process/a3f9c1e0" }

async=true здесь обязателен: реальный скан на 138 страниц обрабатывается около трех минут, а внешний прокси рвет соединение на 300 секундах. Поллинг — тем же ключом:

curl https://api.docinspect.ru/v1/process/a3f9c1e0 -H "X-API-Key: $API_KEY"
{
  "task_id": "a3f9c1e0",
  "status": "done",
  "result": {
    "result": null,
    "documents": [
      { "index": 1, "pages": [1, 24], "doc_type": "Договор аренды № 118-СТ", "confidence": 0.94,
        "result": { "title": "Договор аренды № 118-СТ", "valid_until": "2027-03-31", "total_amount": 2640000.0 } },
      { "index": 2, "pages": [25, 40], "doc_type": "Приложение 1. Спецификация", "confidence": 0.88,
        "result": { "title": "Приложение 1. Спецификация оборудования", "total_amount": null } }
    ],
    "usage": { "pages": 40, "sheets": 40 },
    "metadata": { "extraction_status": "full", "…": "…" }
  },
  "error": null
}

Верхний result при splitnull, данные лежат в documents[]; расход считается по всему файлу разом. Нужны сами PDF-секции (например, чтобы разложить архив по папкам) — добавьте split={"mode":"auto","return_files":true}, и в каждом элементе появится pdf_base64. По умолчанию это выключено, чтобы ответ не раздувался мегабайтами.

Чтобы потом сослаться на конкретный пункт договора, закажите include=["fragments"] — фрагменты приходят с номерами страниц, и ответ ассистента можно проверить, открыв страницу оригинала (см. «fragments»).

On this page