openapi: 3.0.3
info:
  title: DocFila Enterprise API
  version: 1.1.0
  description: |
    Organization-scoped API for documents, e-signatures, workflows, audit
    evidence, webhooks, and SCIM 2.0 provisioning.
servers:
  - url: https://api.docfila.com
    description: Production
security:
  - ApiKeyAuth: []
paths:
  /health:
    get:
      operationId: health.get
      tags: [System]
      summary: Check API availability
      security: []
      responses:
        '200':
          description: API is available
  /v1/account:
    get:
      operationId: account.get
      tags: [Account]
      summary: Get the API key owner's account and subscription summary
      x-docfila-scopes: [accountRead]
      responses:
        '200':
          description: Account summary
  /v1/api-keys:
    post:
      operationId: apiKeys.create
      tags: [API Keys]
      summary: Create a scoped child API key
      x-docfila-scopes: [keysWrite]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [scopes]
              properties:
                name:
                  type: string
                  maxLength: 80
                scopes:
                  type: array
                  minItems: 1
                  uniqueItems: true
                  items:
                    $ref: '#/components/schemas/ApiKeyScope'
      responses:
        '201':
          description: API key created; the plaintext secret is returned once
  /v1/documents:
    get:
      operationId: documents.list
      tags: [Documents]
      summary: List documents
      x-docfila-scopes: [documentsRead]
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: offset
          in: query
          schema:
            type: integer
            minimum: 0
            maximum: 10000
        - name: folder
          in: query
          schema:
            type: string
        - name: type
          in: query
          schema:
            type: string
        - name: sort
          in: query
          schema:
            type: string
            enum: [createdAt, updatedAt, title, type, status]
        - name: order
          in: query
          schema:
            type: string
            enum: [asc, desc]
          description: Filtered lists support only `createdAt` with `desc`.
      responses:
        '200':
          description: Document list
    post:
      operationId: documents.create
      tags: [Documents]
      summary: Create document metadata
      x-docfila-scopes: [documentsWrite]
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateDocument'
      responses:
        '201':
          description: Document created
        '200':
          description: Idempotent replay of the original creation
        '409':
          description: Idempotency key conflicts with another payload
  /v1/documents/{id}:
    get:
      operationId: documents.get
      tags: [Documents]
      summary: Get a document
      x-docfila-scopes: [documentsRead]
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      responses:
        '200':
          description: Document
        '404':
          description: Document not found or not owned by the API principal
    delete:
      operationId: documents.delete
      tags: [Documents]
      summary: Move a document to trash
      description: Legal holds and active retention rules prevent deletion.
      x-docfila-scopes: [documentsWrite]
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      responses:
        '200':
          description: Document moved to trash
        '409':
          description: Deletion blocked by legal hold or retention policy
  /v1/documents/search:
    servers:
      - url: https://us-central1-docfila.cloudfunctions.net/chatgptDocumentsApi
    get:
      operationId: documents.searchText
      tags: [Documents]
      summary: Search owned document titles and extracted text
      x-docfila-scopes: [documentsRead]
      parameters:
        - name: q
          in: query
          required: true
          schema:
            type: string
            minLength: 2
            maxLength: 200
        - name: offset
          in: query
          schema:
            type: integer
            minimum: 0
            maximum: 10000
      responses:
        '200':
          description: Matching titles and text excerpts from up to 50 scanned documents, with a next offset
  /v1/documents/text:
    servers:
      - url: https://us-central1-docfila.cloudfunctions.net/chatgptDocumentsApi
    post:
      operationId: documents.createFromText
      tags: [Documents]
      summary: Create an immutable PDF document from text
      x-docfila-scopes: [documentsWrite]
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [title, text]
              properties:
                title: { type: string, maxLength: 300 }
                text: { type: string, maxLength: 100000 }
                type: { type: string }
                folderId: { type: string }
      responses:
        '201':
          description: PDF document created
        '200':
          description: Idempotent replay
  /v1/documents/{id}/content:
    servers:
      - url: https://us-central1-docfila.cloudfunctions.net/chatgptDocumentsApi
    get:
      operationId: documents.readText
      tags: [Documents]
      summary: Read a chunk of an owned document's extracted text
      x-docfila-scopes: [documentsRead]
      parameters:
        - $ref: '#/components/parameters/ResourceId'
        - name: offset
          in: query
          schema: { type: integer, minimum: 0 }
        - name: limit
          in: query
          schema: { type: integer, minimum: 1, maximum: 16000 }
      responses:
        '200':
          description: Text chunk, total character count, next offset, and content hash
        '422':
          description: No extracted text is available for this file
  /v1/documents/{id}/versions:
    servers:
      - url: https://us-central1-docfila.cloudfunctions.net/chatgptDocumentsApi
    post:
      operationId: documents.saveTextVersion
      tags: [Documents]
      summary: Save edited text as a new immutable PDF version
      description: Preserves the original file. The new PDF does not preserve source layout or non-text elements.
      x-docfila-scopes: [documentsWrite]
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [text, expectedContentHash]
              properties:
                text: { type: string, maxLength: 100000 }
                expectedContentHash: { type: string, pattern: '^[a-f0-9]{64}$' }
                changeDescription: { type: string, maxLength: 300 }
      responses:
        '200':
          description: New PDF version saved
        '409':
          description: Document locked or changed since it was read
        '422':
          description: No extracted text or owned library file is available
  /v1/documents/{id}/upload-url:
    post:
      operationId: documents.uploadUrl.create
      tags: [Documents]
      summary: Create a short-lived PDF upload URL
      x-docfila-scopes: [documentsWrite]
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateDocumentUpload'
      responses:
        '201':
          description: Signed upload URL and required request headers
        '409':
          description: Document already has an immutable source PDF
  /v1/documents/{id}/uploads/complete:
    post:
      operationId: documents.upload.complete
      tags: [Documents]
      summary: Validate and immutably promote an uploaded PDF
      description: Verifies content metadata, PDF magic, SHA-256, and malware scan.
      x-docfila-scopes: [documentsWrite]
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [uploadId]
              properties:
                uploadId:
                  type: string
                  pattern: '^[a-f0-9]{36}$'
      responses:
        '200':
          description: Immutable document source is ready
        '410':
          description: Upload session expired
        '422':
          description: PDF validation, checksum, or security scan failed
  /v1/documents/{id}/download:
    get:
      operationId: documents.download
      tags: [Documents]
      summary: Create a short-lived document download URL
      x-docfila-scopes: [documentsRead]
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      responses:
        '200':
          description: Signed download URL valid for one hour
        '404':
          description: Document or attached file not found
  /v1/folders:
    get:
      operationId: folders.list
      tags: [Folders]
      summary: List folders
      x-docfila-scopes: [foldersRead]
      responses:
        '200':
          description: Folder list
    post:
      operationId: folders.create
      tags: [Folders]
      summary: Create a folder
      x-docfila-scopes: [foldersWrite]
      responses:
        '201':
          description: Folder created
  /v1/export/datev:
    post:
      operationId: documents.export.datev
      tags: [Documents]
      summary: Export up to 500 owned documents as a DATEV-compatible CSV
      x-docfila-scopes: [documentsRead]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [documentIds]
              properties:
                documentIds:
                  type: array
                  minItems: 1
                  maxItems: 500
                  uniqueItems: true
                  items:
                    type: string
                config:
                  type: object
                  additionalProperties: true
      responses:
        '200':
          description: UTF-8 CSV with spreadsheet-formula neutralization
  /v1/documents/{id}/audit-events:
    get:
      operationId: documents.auditEvents
      tags: [Audit]
      summary: List document access events
      x-docfila-scopes: [auditRead]
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      responses:
        '200':
          description: Audit event list
  /v1/workflows/{id}/run:
    post:
      operationId: workflows.run
      tags: [Workflows]
      summary: Run a document workflow
      x-docfila-scopes: [workflowsWrite]
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      responses:
        '202':
          description: Workflow accepted
  /v1/organization/members:
    get:
      operationId: organization.members.list
      tags: [Organization]
      summary: List organization members
      x-docfila-scopes: [membersRead]
      responses:
        '200':
          description: Member list
  /v1/organization/audit-events:
    get:
      operationId: organization.auditEvents.list
      tags: [Audit]
      summary: List organization administration and provisioning events
      x-docfila-scopes: [auditRead]
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 200
        - name: cursor
          in: query
          schema:
            type: string
      responses:
        '200':
          description: Paginated organization audit events
  /v1/signatures/requests:
    post:
      operationId: signatures.requests.create
      tags: [Signatures]
      summary: Create an e-signature envelope
      x-docfila-scopes: [signaturesWrite]
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSignatureRequest'
      responses:
        '201':
          description: Envelope created
        '409':
          description: Idempotency key conflicts with another payload
  /v1/signatures/requests/{id}:
    get:
      operationId: signatures.requests.get
      tags: [Signatures]
      summary: Get envelope status
      x-docfila-scopes: [signaturesRead]
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      responses:
        '200':
          description: Envelope
  /v1/signatures/requests/{id}/evidence:
    get:
      operationId: signatures.requests.evidence
      tags: [Signatures]
      summary: Get hash-chained signature evidence
      x-docfila-scopes: [signaturesRead]
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      responses:
        '200':
          description: Evidence and integrity result
  /v1/signatures/requests/{id}/artifacts/{artifact}:
    get:
      operationId: signatures.requests.artifact
      tags: [Signatures]
      summary: Get a short-lived completed artifact URL
      x-docfila-scopes: [signaturesRead]
      parameters:
        - $ref: '#/components/parameters/ResourceId'
        - name: artifact
          in: path
          required: true
          schema:
            type: string
            enum: [document, certificate]
      responses:
        '200':
          description: Short-lived artifact URL
  /v1/signatures/requests/{id}/embedded-session:
    post:
      operationId: signatures.requests.embeddedSession
      tags: [Signatures]
      summary: Create a short-lived embedded signing session
      x-docfila-scopes: [signaturesWrite]
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      responses:
        '200':
          description: Embedded session
  /v1/signatures/requests/{id}/void:
    post:
      operationId: signatures.requests.void
      tags: [Signatures]
      summary: Void an active envelope
      x-docfila-scopes: [signaturesWrite]
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      responses:
        '200':
          description: Envelope voided
  /v1/signatures/requests/{id}/remind:
    post:
      operationId: signatures.requests.remind
      tags: [Signatures]
      summary: Send a signing reminder
      x-docfila-scopes: [signaturesWrite]
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      responses:
        '200':
          description: Reminder queued
  /v1/signatures/requests/{id}/reassign:
    post:
      operationId: signatures.requests.reassign
      tags: [Signatures]
      summary: Reassign an active envelope
      x-docfila-scopes: [signaturesWrite]
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      responses:
        '200':
          description: Recipient reassigned and old link invalidated
  /v1/signatures/requests/{id}/correct:
    post:
      operationId: signatures.requests.correct
      tags: [Signatures]
      summary: Correct fields on an active envelope
      x-docfila-scopes: [signaturesWrite]
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      responses:
        '200':
          description: Envelope corrected and old link invalidated
  /v1/signatures/workflows/sequential:
    post:
      operationId: signatures.workflows.sequential
      tags: [Signatures]
      summary: Create a sequential signing workflow
      x-docfila-scopes: [signaturesWrite]
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '201':
          description: Sequential workflow created
  /v1/signatures/webhooks:
    get:
      operationId: signatures.webhooks.list
      tags: [Webhooks]
      summary: List signature webhooks
      x-docfila-scopes: [signaturesRead]
      responses:
        '200':
          description: Webhook list
    post:
      operationId: signatures.webhooks.upsert
      tags: [Webhooks]
      summary: Create or update a signature webhook
      x-docfila-scopes: [signaturesWrite]
      responses:
        '201':
          description: Webhook saved; new signing secret is returned once
  /v1/signatures/webhooks/{id}/rotate-secret:
    post:
      operationId: signatures.webhooks.rotateSecret
      tags: [Webhooks]
      summary: Rotate a webhook signing secret
      x-docfila-scopes: [signaturesWrite]
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      responses:
        '200':
          description: New secret returned once
  /v1/signatures/webhooks/{id}:
    delete:
      operationId: signatures.webhooks.delete
      tags: [Webhooks]
      summary: Delete a signature webhook
      x-docfila-scopes: [signaturesWrite]
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      responses:
        '200':
          description: Webhook deleted
  /scim/v2/ServiceProviderConfig:
    get:
      operationId: scim.serviceProviderConfig
      tags: [SCIM]
      summary: Get SCIM capabilities
      x-docfila-scopes: [membersRead]
      security:
        - BearerAuth: []
      responses:
        '200':
          description: SCIM service provider configuration
  /scim/v2/Users:
    get:
      operationId: scim.users.list
      tags: [SCIM]
      summary: List or filter provisioned organization users
      x-docfila-scopes: [membersRead]
      security:
        - BearerAuth: []
      parameters:
        - name: filter
          in: query
          schema:
            type: string
          description: Supports `userName eq "person@example.com"`.
        - name: startIndex
          in: query
          schema:
            type: integer
            minimum: 1
        - name: count
          in: query
          schema:
            type: integer
            minimum: 0
            maximum: 200
      responses:
        '200':
          description: SCIM ListResponse
    post:
      operationId: scim.users.create
      tags: [SCIM]
      summary: Provision an organization user
      x-docfila-scopes: [membersWrite]
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/scim+json:
            schema:
              $ref: '#/components/schemas/ScimUser'
      responses:
        '201':
          description: SCIM user created
        '409':
          description: userName already exists in the organization
  /scim/v2/Users/{id}:
    get:
      operationId: scim.users.get
      tags: [SCIM]
      summary: Get a provisioned user
      x-docfila-scopes: [membersRead]
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      responses:
        '200':
          description: SCIM user
    patch:
      operationId: scim.users.patch
      tags: [SCIM]
      summary: Update or deactivate a provisioned user
      x-docfila-scopes: [membersWrite]
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      responses:
        '200':
          description: Updated SCIM user
    delete:
      operationId: scim.users.deactivate
      tags: [SCIM]
      summary: Deactivate organization membership
      x-docfila-scopes: [membersWrite]
      security:
        - BearerAuth: []
      parameters:
        - $ref: '#/components/parameters/ResourceId'
      responses:
        '204':
          description: Membership deactivated
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-Api-Key
    BearerAuth:
      type: http
      scheme: bearer
  parameters:
    ResourceId:
      name: id
      in: path
      required: true
      schema:
        type: string
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      schema:
        type: string
        minLength: 8
        maxLength: 128
  schemas:
    ApiKeyScope:
      type: string
      enum:
        - accountRead
        - documentsRead
        - documentsWrite
        - foldersRead
        - foldersWrite
        - sharingWrite
        - signaturesRead
        - signaturesWrite
        - workflowsWrite
        - membersRead
        - membersWrite
        - auditRead
        - keysWrite
    CreateSignatureRequest:
      type: object
      required: [documentId, signerEmail, fields]
      properties:
        documentId:
          type: string
        signerEmail:
          type: string
          format: email
        documentTitle:
          type: string
        fields:
          type: array
          minItems: 1
          maxItems: 200
          items:
            $ref: '#/components/schemas/SignatureField'
    CreateDocument:
      type: object
      required: [title]
      properties:
        title:
          type: string
          minLength: 1
          maxLength: 300
        type:
          type: string
          pattern: '^[a-z][A-Za-z0-9_]{0,63}$'
          default: other
        folderId:
          type: string
          nullable: true
          pattern: '^[A-Za-z0-9_-]+$'
        metadata:
          type: object
          description: Maximum encoded size 64 KiB; compliance fields are server-managed.
          additionalProperties: true
    CreateDocumentUpload:
      type: object
      required: [contentLength]
      properties:
        contentLength:
          type: integer
          minimum: 5
          maximum: 104857600
        sha256:
          type: string
          pattern: '^[a-fA-F0-9]{64}$'
    SignatureField:
      type: object
      required: [type, pageNumber, x, y, width, height]
      properties:
        id:
          type: string
          maxLength: 128
        type:
          type: string
          enum: [signature, initials, date, name, email, text, checkbox]
        pageNumber:
          type: integer
          minimum: 1
        x:
          type: number
          minimum: 0
          maximum: 1
        y:
          type: number
          minimum: 0
          maximum: 1
        width:
          type: number
          exclusiveMinimum: true
          minimum: 0
          maximum: 1
        height:
          type: number
          exclusiveMinimum: true
          minimum: 0
          maximum: 1
        isRequired:
          type: boolean
          default: true
    ScimUser:
      type: object
      required: [userName]
      properties:
        schemas:
          type: array
          items:
            type: string
        id:
          type: string
          readOnly: true
        externalId:
          type: string
        userName:
          type: string
          format: email
        active:
          type: boolean
        displayName:
          type: string
        name:
          type: object
          properties:
            givenName:
              type: string
            familyName:
              type: string
        roles:
          type: array
          items:
            type: object
            properties:
              value:
                type: string
                enum: [admin, member, viewer]
