openapi: 3.0.3
info:
  title: Invico API
  version: "1.0"
  description: >
    Veřejné /v1 rozhraní Invico — doklady, kontakty, náklady, kolekce.
    Auth: Bearer PAT (invk_…), scope read|write, per-key rate 2 r/s + burst 30.
    Vše company-scoped — klíč nese firmu.
servers:
  - url: https://app.invico.org
paths:
  /v1/ping:
    get:
      summary: Verify key
      responses:
        "200":
          description: ok
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  company: { type: string }
  /v1/documents:
    get:
      summary: List documents
      parameters:
        - { name: status, in: query, schema: { type: string }, description: "comma list — issued,sent,overdue = unpaid surface" }
        - { name: kind, in: query, schema: { type: string } }
        - { name: contactId, in: query, schema: { type: string } }
        - { name: limit, in: query, schema: { type: integer } }
        - { name: offset, in: query, schema: { type: integer } }
      responses:
        "200": { description: "{ data: Document[] }" }
    post:
      summary: Create or update a document (idempotent with own id)
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/Document" }
      responses:
        "200": { description: saved doc }
        "409": { description: number_taken — řada number already claimed }
  /v1/documents/bulk:
    post:
      summary: Batch document create
      responses: { "200": { description: results per row } }
  /v1/documents/{id}:
    get:
      summary: Document + items + payments + events
      parameters: [ { name: id, in: path, required: true, schema: { type: string } } ]
      responses:
        "200": { description: Document }
        "404": { description: not found }
    put:
      summary: Update document
      parameters: [ { name: id, in: path, required: true, schema: { type: string } } ]
      responses: { "200": { description: saved doc } }
    delete:
      summary: Delete document
      parameters: [ { name: id, in: path, required: true, schema: { type: string } } ]
      responses: { "204": { description: deleted } }
  /v1/documents/{id}/status:
    post:
      summary: Transition status
      parameters: [ { name: id, in: path, required: true, schema: { type: string } } ]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                status: { type: string, enum: [issued, sent, paid, cancelled] }
      responses: { "200": { description: updated } }
  /v1/documents/{id}/payments:
    post:
      summary: Record a payment (partial allowed)
      parameters: [ { name: id, in: path, required: true, schema: { type: string } } ]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                amount: { type: integer, description: haléře }
                currency: { type: string }
                paidAt: { type: string, format: date }
                method: { type: string }
                note: { type: string }
      responses: { "200": { description: recorded } }
  /v1/documents/{id}/finalize:
    post:
      summary: Draft → issued (+ mail when configured)
      parameters: [ { name: id, in: path, required: true, schema: { type: string } } ]
      responses: { "200": { description: issued doc } }
  /v1/documents/{id}/send:
    post:
      summary: Send the doc mail
      parameters: [ { name: id, in: path, required: true, schema: { type: string } } ]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties: { to: { type: string } }
      responses: { "200": { description: queued/sent } }
  /v1/documents/{id}/attachments:
    post:
      summary: Attach file (multipart)
      parameters: [ { name: id, in: path, required: true, schema: { type: string } } ]
      responses: { "201": { description: file row } }
  /v1/contacts:
    get:
      summary: List contacts
      responses: { "200": { description: "{ data: Contact[] }" } }
    post:
      summary: Upsert contact
      requestBody:
        content:
          application/json:
            schema: { $ref: "#/components/schemas/Contact" }
      responses: { "200": { description: saved contact } }
  /v1/contacts/{id}:
    get: { summary: Get contact, parameters: [ { name: id, in: path, required: true, schema: { type: string } } ], responses: { "200": { description: Contact } } }
    put: { summary: Update contact, parameters: [ { name: id, in: path, required: true, schema: { type: string } } ], responses: { "200": { description: saved } } }
    delete: { summary: Delete contact, parameters: [ { name: id, in: path, required: true, schema: { type: string } } ], responses: { "204": { description: deleted } } }
  /v1/expenses:
    get: { summary: List expenses, responses: { "200": { description: "{ data: Expense[] }" } } }
    post:
      summary: Upsert expense (recurEvery/recurNext for recurring)
      responses: { "200": { description: saved expense } }
  /v1/expenses/{id}:
    get: { summary: Get expense, parameters: [ { name: id, in: path, required: true, schema: { type: string } } ], responses: { "200": { description: Expense } } }
    put: { summary: Update expense, parameters: [ { name: id, in: path, required: true, schema: { type: string } } ], responses: { "200": { description: saved } } }
    delete: { summary: Delete expense, parameters: [ { name: id, in: path, required: true, schema: { type: string } } ], responses: { "204": { description: deleted } } }
  /v1/collections/{kind}:
    get:
      summary: Generic collections (categories, projects, folders, priceList)
      parameters: [ { name: kind, in: path, required: true, schema: { type: string } } ]
      responses: { "200": { description: rows } }
  /v1/ares:
    get:
      summary: ARES registry lookup
      parameters: [ { name: ico, in: query, required: true, schema: { type: string } } ]
      responses: { "200": { description: entity data } }
  /v1/legal:
    get: { summary: Czech legal corpus index, responses: { "200": { description: entries } } }
  /v1/legal/{id}:
    get: { summary: Legal corpus entry, parameters: [ { name: id, in: path, required: true, schema: { type: string } } ], responses: { "200": { description: entry } } }
  /v1/mcp:
    post:
      summary: MCP JSON-RPC tool surface for agents
      responses: { "200": { description: JSON-RPC response } }
components:
  securitySchemes:
    bearer: { type: http, scheme: bearer }
  schemas:
    Document:
      type: object
      properties:
        id: { type: string }
        kind: { type: string, enum: [invoice, proforma, quote, credit_note, delivery_note, receipt, order, purchase_order, ddpp, received] }
        number: { type: string }
        status: { type: string }
        contactId: { type: string }
        issuedAt: { type: string, format: date }
        duzp: { type: string, format: date }
        dueAt: { type: string, format: date }
        currency: { type: string }
        variableSymbol: { type: string }
        language: { type: string }
        installments:
          type: array
          description: splátkový kalendář — sum(amount) must equal doc total
          items:
            type: object
            properties:
              due: { type: string, format: date }
              amount: { type: integer, description: haléře }
        items:
          type: array
          items:
            type: object
            properties:
              title: { type: string }
              qty: { type: number }
              unit: { type: string }
              unitPrice: { type: integer, description: haléře }
              vatRate: { type: number }
    Contact:
      type: object
      properties:
        name: { type: string }
        ico: { type: string }
        dic: { type: string }
        address: { type: string }
        email: { type: string }
        kind: { type: string, enum: [customer, supplier] }
security:
  - bearer: []
