openapi: 3.0.3
info:
  title: Enso Billing Integration API
  version: 1.0.0
  description: |
    Partner-facing API for creating and fetching invoices using a per-company API key.
    Company administrators generate keys via `POST /api/integration-key/generate` (Sanctum auth).
servers:
  - url: /api
    description: API base path
security:
  - apiKeyAuth: []
tags:
  - name: Invoices
    description: Create and fetch sale invoices
  - name: Payments
    description: Record and void customer payments
  - name: Credit Notes
    description: Refunds against sale returns (credit notes)
  - name: API Keys
    description: Company admin key management (Sanctum)
  - name: Company
    description: Company master data for integration partners
paths:
  /integration/v1/bank-accounts:
    get:
      tags: [Company]
      summary: List company bank accounts usable for integration payments
      description: |
        Returns active company bank accounts that have bank name and account number on file
        (`can_use_for_payments: true`). Use an account `id` as `company_bank_account_id` when
        recording bank payments on invoices.
      operationId: listBankAccounts
      responses:
        '200':
          description: Payable bank accounts for the API key company
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CompanyBankAccountListEnvelope'
              example:
                status: true
                message: null
                data:
                  - id: 1
                    label: Main account
                    account_holder_name: Acme Pvt Ltd
                    bank_name: HDFC Bank
                    account_number: '1234567890'
                    ifsc: HDFC0001234
                    can_use_for_payments: true
                    sort_order: 0
        '401':
          $ref: '#/components/responses/Unauthorized'
  /integration/v1/invoices:
    post:
      tags: [Invoices]
      summary: Create a sale invoice
      operationId: createInvoice
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InvoiceCreateRequest'
            example:
              invoice_date: '2026-07-03'
              customer:
                name: Rahul Sharma
                phone: '9876543210'
              lines:
                - name: Consulting
                  quantity: 1
                  unit_price: 5000
                  gst_rate: 18
      responses:
        '201':
          description: Invoice created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvoiceDetailEnvelope'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'
    get:
      tags: [Invoices]
      summary: List sale invoices
      operationId: listInvoices
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: per_page
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 10
        - name: customer_phone
          in: query
          schema:
            type: string
        - name: invoice_date
          in: query
          schema:
            type: string
            format: date
        - name: invoice_number
          in: query
          schema:
            type: string
      responses:
        '200':
          description: Paginated invoice list
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvoiceListEnvelope'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /integration/v1/invoices/{id}:
    get:
      tags: [Invoices]
      summary: Fetch a single invoice
      operationId: getInvoice
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Invoice detail
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvoiceDetailEnvelope'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
  /integration/v1/invoices/{id}/download:
    get:
      tags: [Invoices]
      summary: Download sale invoice PDF
      operationId: downloadInvoicePdf
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Invoice PDF file
          content:
            application/pdf:
              schema:
                type: string
                format: binary
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
  /integration/v1/invoices/{id}/payments:
    post:
      tags: [Invoices]
      summary: Record payment on a sale invoice
      operationId: recordInvoicePayment
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PaymentInput'
      responses:
        '200':
          description: Payment recorded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiEnvelope'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'
  /integration/v1/invoices/{id}/void:
    post:
      tags: [Invoices]
      summary: Void a sale invoice
      operationId: voidInvoice
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Invoice voided
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvoiceDetailEnvelope'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'
  /integration/v1/payments/{id}/void:
    post:
      tags: [Payments]
      summary: Void a customer payment
      operationId: voidPayment
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Payment voided
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiEnvelope'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
  /integration/v1/credit-notes/{id}/refunds:
    get:
      tags: [Credit Notes]
      summary: Refund summary for a credit note
      operationId: creditNoteRefundSummary
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Refund summary
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiEnvelope'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      tags: [Credit Notes]
      summary: Record refund on a credit note
      operationId: recordCreditNoteRefund
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RefundInput'
      responses:
        '200':
          description: Refund recorded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiEnvelope'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'
  /integration-key/generate:
    post:
      tags: [API Keys]
      summary: Generate API key (company admin, Sanctum)
      security:
        - sanctumAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
                  maxLength: 100
      responses:
        '201':
          description: Key created (full secret shown once)
components:
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: X-Api-Key
    sanctumAuth:
      type: http
      scheme: bearer
  schemas:
    ApiEnvelope:
      type: object
      properties:
        status:
          type: boolean
        message:
          type: string
          nullable: true
        data:
          nullable: true
        meta:
          type: object
          nullable: true
        errors:
          type: object
          nullable: true
        code:
          type: string
          nullable: true
    CustomerInput:
      type: object
      required: [name, phone]
      properties:
        name:
          type: string
        phone:
          type: string
        address:
          type: string
        pincode:
          type: string
        gst_number:
          type: string
        state_code:
          type: string
    LineInput:
      type: object
      required: [quantity, unit_price]
      properties:
        product_id:
          type: integer
        name:
          type: string
        quantity:
          type: integer
          minimum: 1
        unit_price:
          type: number
          minimum: 0
        gst_rate:
          type: number
        hsn_code:
          type: string
    InvoiceCreateRequest:
      type: object
      required: [invoice_date, customer, lines]
      properties:
        invoice_date:
          type: string
          format: date
        due_date:
          type: string
          format: date
        notes:
          type: string
        external_reference:
          type: string
        customer:
          $ref: '#/components/schemas/CustomerInput'
        lines:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/LineInput'
        payments:
          type: array
          items:
            $ref: '#/components/schemas/PaymentInput'
        charges:
          type: array
          items:
            $ref: '#/components/schemas/ChargeInput'
    PaymentInput:
      type: object
      properties:
        paid_amount:
          type: number
          minimum: 0
        payment_date:
          type: string
          format: date
        payment_mode:
          type: string
          enum: [cash, bank]
        company_bank_account_id:
          type: integer
        reference_type:
          type: string
          enum: [utr, cheque, neft, rtgs, imps, upi, other]
        reference_number:
          type: string
        notes:
          type: string
    ChargeInput:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        amount:
          type: number
          minimum: 0
        description:
          type: string
    RefundInput:
      type: object
      required: [amount, payment_mode]
      properties:
        amount:
          type: number
          minimum: 0.01
        refund_date:
          type: string
          format: date
        payment_date:
          type: string
          format: date
        payment_mode:
          type: string
          enum: [cash, bank]
        company_bank_account_id:
          type: integer
        reference_type:
          type: string
        reference_number:
          type: string
        notes:
          type: string
    InvoiceDetail:
      type: object
      properties:
        id:
          type: integer
        display_number:
          type: string
        invoice_date:
          type: string
        total_amount:
          type: number
        payment_status:
          type: string
        customer:
          type: object
        lines:
          type: array
          items:
            type: object
    InvoiceDetailEnvelope:
      allOf:
        - $ref: '#/components/schemas/ApiEnvelope'
        - type: object
          properties:
            data:
              $ref: '#/components/schemas/InvoiceDetail'
    InvoiceListEnvelope:
      allOf:
        - $ref: '#/components/schemas/ApiEnvelope'
        - type: object
          properties:
            data:
              type: array
              items:
                type: object
            meta:
              type: object
              properties:
                current_page:
                  type: integer
                last_page:
                  type: integer
                per_page:
                  type: integer
                total:
                  type: integer
    CompanyBankAccount:
      type: object
      properties:
        id:
          type: integer
        label:
          type: string
          nullable: true
        account_holder_name:
          type: string
        bank_name:
          type: string
        account_number:
          type: string
        ifsc:
          type: string
          nullable: true
        can_use_for_payments:
          type: boolean
          description: True when bank name and account number are on file
        sort_order:
          type: integer
    CompanyBankAccountListEnvelope:
      allOf:
        - $ref: '#/components/schemas/ApiEnvelope'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/CompanyBankAccount'
  responses:
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiEnvelope'
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiEnvelope'
    ValidationError:
      description: Validation or business rule failure
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiEnvelope'
