openapi: 3.1.0 info: title: Парсек API version: "1.0.0" summary: Извлечение данных из счетов, УПД, актов и кассовых чеков description: | REST API для распознавания финансовых документов. Возвращает структурированные поля, уверенность по полям и результаты проверок (контрольные суммы ИНН, арифметика, НДС). Демо-спецификация портфолио-проекта. Локальная реализация: `node mock-server/server.js`. contact: email: dev@parsek.example license: name: Лицензионный договор url: https://parsek.example/legal/offer.html servers: - url: https://api.parsek.example/v1 description: Боевой API - url: http://localhost:4545/v1 description: Локальный мок-сервер security: - bearerAuth: [] tags: - name: Документы - name: Использование - name: Вебхуки paths: /documents: post: tags: [Документы] operationId: createDocument summary: Загрузить документ на распознавание parameters: - name: wait in: query description: Ждать результат до 30 секунд и вернуть 200 вместо 202 schema: { type: boolean, default: false } - $ref: "#/components/parameters/IdempotencyKey" requestBody: required: true content: multipart/form-data: schema: type: object properties: file: type: string format: binary description: PDF, JPG, PNG, HEIC, TIFF или WEBP до 20 МБ type: $ref: "#/components/schemas/DocumentTypeParam" options[validate]: { type: boolean, default: true } options[return_boxes]: { type: boolean, default: false } options[egrul_check]: { type: boolean, default: false } options[fns_check]: { type: boolean, default: false } metadata: type: string description: JSON-объект до 20 пар ключ-значение required: [file] encoding: file: contentType: application/pdf, image/jpeg, image/png, image/heic, image/tiff, image/webp application/json: schema: type: object properties: url: { type: string, format: uri, description: HTTPS-ссылка на файл } type: { $ref: "#/components/schemas/DocumentTypeParam" } options: type: object properties: validate: { type: boolean } return_boxes: { type: boolean } metadata: type: object additionalProperties: { type: string } required: [url] application/pdf: schema: { type: string, format: binary } responses: "200": description: Документ обработан (wait=true) headers: X-Request-Id: { $ref: "#/components/headers/RequestId" } X-RateLimit-Remaining: { $ref: "#/components/headers/RateLimitRemaining" } content: application/json: schema: { $ref: "#/components/schemas/Document" } "202": description: Принято в обработку, результат придёт вебхуком headers: Location: { schema: { type: string }, description: URL документа } content: application/json: schema: { $ref: "#/components/schemas/Document" } "400": { $ref: "#/components/responses/Error" } "401": { $ref: "#/components/responses/Error" } "402": { $ref: "#/components/responses/Error" } "409": { $ref: "#/components/responses/Error" } "413": { $ref: "#/components/responses/Error" } "415": { $ref: "#/components/responses/Error" } "422": { $ref: "#/components/responses/Error" } "429": { $ref: "#/components/responses/Error" } get: tags: [Документы] operationId: listDocuments summary: Список документов parameters: - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 20 } } - { name: starting_after, in: query, schema: { type: string }, description: Курсор — id последнего документа предыдущей страницы } - { name: status, in: query, schema: { $ref: "#/components/schemas/DocumentStatus" } } - { name: type, in: query, schema: { $ref: "#/components/schemas/DocumentType" } } responses: "200": description: Страница списка content: application/json: schema: type: object properties: object: { type: string, const: list } data: { type: array, items: { $ref: "#/components/schemas/Document" } } has_more: { type: boolean } "401": { $ref: "#/components/responses/Error" } /documents/{id}: parameters: - { name: id, in: path, required: true, schema: { type: string, pattern: "^doc_" } } get: tags: [Документы] operationId: getDocument summary: Получить документ responses: "200": description: Документ content: application/json: schema: { $ref: "#/components/schemas/Document" } "404": { $ref: "#/components/responses/Error" } delete: tags: [Документы] operationId: deleteDocument summary: Удалить файл и результат responses: "200": description: Удалено content: application/json: schema: type: object properties: id: { type: string } deleted: { type: boolean, const: true } "404": { $ref: "#/components/responses/Error" } /usage: get: tags: [Использование] operationId: getUsage summary: Расход страниц за месяц parameters: - { name: period, in: query, schema: { type: string, pattern: "^\\d{4}-\\d{2}$" }, example: "2026-09" } responses: "200": description: Статистика content: application/json: schema: type: object properties: period: { type: string } pages: { type: integer } included: { type: integer } overage_pages: { type: integer } requests: { type: integer } /webhook_endpoints: post: tags: [Вебхуки] operationId: createWebhookEndpoint summary: Добавить эндпоинт вебхуков requestBody: required: true content: application/json: schema: type: object required: [url] properties: url: { type: string, format: uri } events: type: array items: { type: string, enum: [document.processed, document.failed, usage.threshold] } responses: "201": description: Создан. Секрет показывается один раз. content: application/json: schema: type: object properties: id: { type: string } url: { type: string } events: { type: array, items: { type: string } } secret: { type: string, example: whsec_5d2c8e1f0a9b7c3d } webhooks: document.processed: post: summary: Документ обработан parameters: - name: Parsek-Signature in: header required: true description: "t={unix},v1={hex(HMAC-SHA256(secret, t + '.' + body))}" schema: { type: string } requestBody: content: application/json: schema: { $ref: "#/components/schemas/Event" } responses: "200": { description: Событие принято } components: securitySchemes: bearerAuth: type: http scheme: bearer description: "psk_test_… — тестовая среда, psk_live_… — боевая" parameters: IdempotencyKey: name: Idempotency-Key in: header description: Повтор с тем же ключом 24 часа возвращает исходный ответ без тарификации schema: { type: string, maxLength: 255 } headers: RequestId: schema: { type: string, example: req_7Hc2Pq91 } RateLimitRemaining: schema: { type: integer } responses: Error: description: Ошибка content: application/json: schema: { $ref: "#/components/schemas/Error" } schemas: DocumentType: type: string enum: [invoice, upd, vat_invoice, act, torg12, receipt, company_card, bank_statement] DocumentTypeParam: type: string enum: [auto, invoice, upd, vat_invoice, act, torg12, receipt, company_card] default: auto DocumentStatus: type: string enum: [processing, processed, failed] Party: type: object properties: name: { type: string, example: ООО «ТЕХСНАБ» } inn: { type: string, pattern: "^(\\d{10}|\\d{12})$", example: "7700000009" } kpp: { type: [string, "null"], pattern: "^\\d{9}$", example: "770001001" } address: { type: string } Money: type: number description: Сумма в рублях с копейками example: 41560.00 VatRate: type: string enum: ["22%", "10%", "0%", none] InvoiceData: type: object properties: number: { type: string } date: { type: string, format: date } currency: { type: string, example: RUB } supplier: allOf: - $ref: "#/components/schemas/Party" - type: object properties: bank: type: object properties: name: { type: string } bik: { type: string, pattern: "^\\d{9}$" } account: { type: string, pattern: "^\\d{20}$" } corr_account: { type: string, pattern: "^\\d{20}$" } buyer: { $ref: "#/components/schemas/Party" } items: type: array items: type: object properties: name: { type: string } quantity: { type: number } unit: { type: string } price: { $ref: "#/components/schemas/Money" } amount: { $ref: "#/components/schemas/Money" } vat_rate: { $ref: "#/components/schemas/VatRate" } total: { $ref: "#/components/schemas/Money" } vat_rate: { $ref: "#/components/schemas/VatRate" } vat_amount: { $ref: "#/components/schemas/Money" } amount_due: { $ref: "#/components/schemas/Money" } payment_purpose: { type: string } UpdData: type: object properties: status: { type: string, enum: ["1", "2"] } number: { type: string } date: { type: string, format: date } seller: { $ref: "#/components/schemas/Party" } buyer: { $ref: "#/components/schemas/Party" } items: type: array items: type: object properties: name: { type: string } code: { type: string, description: Код ОКЕИ } unit: { type: string } quantity: { type: number } price: { $ref: "#/components/schemas/Money" } amount_without_vat: { $ref: "#/components/schemas/Money" } vat_rate: { $ref: "#/components/schemas/VatRate" } vat_amount: { $ref: "#/components/schemas/Money" } amount: { $ref: "#/components/schemas/Money" } total_without_vat: { $ref: "#/components/schemas/Money" } vat_amount: { $ref: "#/components/schemas/Money" } total: { $ref: "#/components/schemas/Money" } basis: { type: string } shipped_at: { type: string, format: date } ReceiptData: type: object properties: seller: { $ref: "#/components/schemas/Party" } datetime: { type: string, format: date-time } operation: { type: string, enum: [income, income_return, expense, expense_return] } tax_system: { type: string, example: usn_income } items: type: array items: type: object properties: name: { type: string } quantity: { type: number } price: { $ref: "#/components/schemas/Money" } amount: { $ref: "#/components/schemas/Money" } vat: { type: string } total: { $ref: "#/components/schemas/Money" } payment: type: object properties: cash: { $ref: "#/components/schemas/Money" } card: { $ref: "#/components/schemas/Money" } fiscal: type: object properties: fn: { type: string } fd: { type: string } fp: { type: string } qr: { type: string } Check: type: object properties: code: { type: string, example: inn_checksum } field: { type: string, example: supplier.inn } status: { type: string, enum: [passed, warning, failed, skipped] } message: { type: string } Document: type: object required: [id, object, status, livemode] properties: id: { type: string, example: doc_8Kq2nX4vT1pR } object: { type: string, const: document } status: { $ref: "#/components/schemas/DocumentStatus" } type: { oneOf: [{ $ref: "#/components/schemas/DocumentType" }, { type: "null" }] } type_confidence: { type: number, minimum: 0, maximum: 1 } filename: { type: string } pages: { type: integer } created_at: { type: string, format: date-time } processing_ms: { type: integer } livemode: { type: boolean } data: oneOf: - $ref: "#/components/schemas/InvoiceData" - $ref: "#/components/schemas/UpdData" - $ref: "#/components/schemas/ReceiptData" confidence: type: object additionalProperties: { type: number } validation: type: object properties: passed: { type: boolean } warnings: { type: integer } checks: { type: array, items: { $ref: "#/components/schemas/Check" } } metadata: type: object additionalProperties: { type: string } error: oneOf: [{ $ref: "#/components/schemas/ErrorBody" }, { type: "null" }] Event: type: object properties: id: { type: string, example: evt_2Lm9Qx7 } object: { type: string, const: event } type: { type: string, enum: [document.processed, document.failed, usage.threshold] } created_at: { type: string, format: date-time } livemode: { type: boolean } data: { type: object } ErrorBody: type: object properties: type: { type: string, enum: [invalid_request_error, authentication_error, rate_limit_error, api_error] } code: type: string enum: [invalid_request, unauthorized, quota_exceeded, forbidden, not_found, idempotency_conflict, file_too_large, unsupported_media_type, unprocessable_document, rate_limited, server_error] message: { type: string } param: { type: string } request_id: { type: string } Error: type: object properties: error: { $ref: "#/components/schemas/ErrorBody" }