> ## Documentation Index
> Fetch the complete documentation index at: https://docs.watchdoc.sphinxhq.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Submit a document

> Upload a `file` (multipart) or pass a `url` (JSON). Returns `201` immediately with `status: processing`. Poll the retrieve endpoint, or pass `webhook_url` to be pushed the result.



## OpenAPI

````yaml /api_schema.yaml post /api/v1/document-checks/
openapi: 3.0.3
info:
  title: Sphinx Document Fraud API
  version: 1.0.0
  description: >
    Detect forged, tampered, and AI-generated documents. Upload a PDF or image
    and get back a

    structured verdict with a defined set of fraud flags.


    **Quick Start:**

    1. **Create an API key**: sign up, then generate a key from Settings.

    2. **Submit a document**: `POST /api/v1/document-checks/` with a file or a
    URL.
       You get back an id with status `"processing"`.
    3. **Poll for the result**: `GET /api/v1/document-checks/{id}/` until status
    is
       `"completed"` or `"failed"`.

    Optionally pass `webhook_url` on submit to be notified when analysis
    finishes, or

    `?wait=true` to block the submit request for up to 55s.


    **Authentication:** `Authorization: Bearer <api_key>`


    **Decisions:** Every completed check returns a decision (`clear`, `pending`,
    `suspicious`, or

    `fraudulent`), a `risk_level`, a plain-language summary, structured flags,
    and any

    workspace rules that triggered. The four-value decision set is the v1
    contract.
servers:
  - url: /
    description: This environment
security: []
tags:
  - name: Document Checks
    description: |-
      Submit a document for fraud analysis and retrieve structured results.

      **Allowed file types:** PDF, PNG, JPG.
  - name: Rules
    description: >-
      Workspace rules that guide the fraud engine, plus the score cut lines that
      set the `action` field on each check.
paths:
  /api/v1/document-checks/:
    post:
      tags:
        - Document Checks
      summary: Submit a document
      description: >-
        Upload a `file` (multipart) or pass a `url` (JSON). Returns `201`
        immediately with `status: processing`. Poll the retrieve endpoint, or
        pass `webhook_url` to be pushed the result.
      operationId: v1_document_checks_create
      parameters:
        - in: query
          name: wait
          schema:
            type: boolean
          description: >-
            Block this request for up to 55s while analysis runs. Prefer
            polling; if analysis takes longer than the budget, the response is
            still the processing check.
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DocumentCheckCreate'
            examples:
              SubmitByURL:
                value:
                  url: https://example.com/statement.pdf
                  mode: normal
                summary: Submit by URL
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/DocumentCheckCreate'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/DocumentCheckCreate'
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DocumentCheck'
          description: The created check.
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: Invalid input. See `error.message`.
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: Missing or invalid API key.
        '402':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: The workspace is out of document check credits.
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: The key's workspace role lacks the required permission.
        '429':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: Too many requests. Retry after the window resets.
      security:
        - ApiKeyAuth: []
components:
  schemas:
    DocumentCheckCreate:
      type: object
      description: >-
        Input validation for `POST /v1/document-checks`.


        Accepts either a multipart `file` or a JSON `url`; exactly one is
        required.
      properties:
        file:
          type: string
          format: uri
        url:
          type: string
          format: uri
          maxLength: 2048
        mode:
          allOf:
            - $ref: '#/components/schemas/ModeEnum'
          default: normal
        webhook_url:
          type: string
          format: uri
          default: ''
          maxLength: 1024
    DocumentCheck:
      type: object
      description: >-
        The `document_check` object returned by submit, retrieve, list, and
        webhooks.
      properties:
        id:
          type: string
          description: Prefixed id, e.g. `dc_9f2c…`.
        object:
          type: string
          default: document_check
        created_at:
          type: string
        status:
          $ref: '#/components/schemas/DocumentCheckStatusEnum'
        decision:
          nullable: true
          description: >-
            Null until the check completes. Reflects a dashboard override when
            one exists.


            * `clear` - clear

            * `pending` - pending

            * `suspicious` - suspicious

            * `fraudulent` - fraudulent
          oneOf:
            - $ref: '#/components/schemas/DecisionEnum'
            - $ref: '#/components/schemas/NullEnum'
        risk_level:
          nullable: true
          oneOf:
            - $ref: '#/components/schemas/RiskLevelEnum'
            - $ref: '#/components/schemas/NullEnum'
        risk_score:
          type: integer
          maximum: 100
          minimum: 0
          nullable: true
          description: >-
            0-100, higher is riskier. Decision bands: clear 0-39, pending 40-59,
            suspicious 60-79, fraudulent 80-100.
        action:
          nullable: true
          description: |-
            Workflow routing from workspace thresholds. Not a verdict.

            * `approve` - approve
            * `review` - review
            * `reject` - reject
          oneOf:
            - $ref: '#/components/schemas/ActionEnum'
            - $ref: '#/components/schemas/NullEnum'
        thresholds:
          allOf:
            - $ref: '#/components/schemas/Thresholds'
          description: The cut lines this check was scored against.
        summary:
          type: string
          nullable: true
        flags:
          type: array
          items:
            $ref: '#/components/schemas/Flag'
        rules:
          type: array
          items:
            $ref: '#/components/schemas/TriggeredRule'
          description: Workspace rules that fired on this document.
        document:
          $ref: '#/components/schemas/DocumentInfo'
        extracted:
          $ref: '#/components/schemas/ExtractedFields'
        engine:
          $ref: '#/components/schemas/EngineInfo'
        error:
          type: string
          nullable: true
          description: Set only when `status` is `failed`.
      required:
        - action
        - created_at
        - decision
        - document
        - engine
        - error
        - extracted
        - flags
        - id
        - risk_level
        - risk_score
        - rules
        - status
        - summary
        - thresholds
    Error:
      type: object
      properties:
        error:
          $ref: '#/components/schemas/ErrorDetail'
      required:
        - error
    ModeEnum:
      enum:
        - strict
        - normal
        - lenient
      type: string
      description: |-
        * `strict` - strict
        * `normal` - normal
        * `lenient` - lenient
    DocumentCheckStatusEnum:
      enum:
        - processing
        - completed
        - failed
      type: string
      description: |-
        * `processing` - processing
        * `completed` - completed
        * `failed` - failed
    DecisionEnum:
      enum:
        - clear
        - pending
        - suspicious
        - fraudulent
      type: string
      description: |-
        * `clear` - clear
        * `pending` - pending
        * `suspicious` - suspicious
        * `fraudulent` - fraudulent
    NullEnum:
      enum:
        - null
    RiskLevelEnum:
      enum:
        - LOW
        - MEDIUM
        - HIGH
      type: string
      description: |-
        * `LOW` - LOW
        * `MEDIUM` - MEDIUM
        * `HIGH` - HIGH
    ActionEnum:
      enum:
        - approve
        - review
        - reject
      type: string
      description: |-
        * `approve` - approve
        * `review` - review
        * `reject` - reject
    Thresholds:
      type: object
      properties:
        pass_below:
          type: integer
          maximum: 100
          minimum: 0
        review_below:
          type: integer
          maximum: 100
          minimum: 0
      required:
        - pass_below
        - review_below
    Flag:
      type: object
      properties:
        code:
          $ref: '#/components/schemas/FlagCodeEnum'
        category:
          type: string
        severity:
          $ref: '#/components/schemas/SeverityEnum'
        title:
          type: string
        description:
          type: string
        pages:
          type: array
          items:
            type: integer
        reasons:
          type: array
          items:
            $ref: '#/components/schemas/FlagReason'
          description: The observations behind this flag. Always at least one.
      required:
        - category
        - code
        - description
        - pages
        - reasons
        - severity
        - title
    TriggeredRule:
      type: object
      properties:
        id:
          type: string
        title:
          type: string
        outcome_guidance:
          nullable: true
          oneOf:
            - $ref: '#/components/schemas/OutcomeGuidanceEnum'
            - $ref: '#/components/schemas/NullEnum'
        score_delta:
          type: integer
        reasoning:
          type: string
      required:
        - id
        - outcome_guidance
        - reasoning
        - score_delta
        - title
    DocumentInfo:
      type: object
      properties:
        filename:
          type: string
        mime_type:
          type: string
        pages:
          type: integer
          nullable: true
        size_bytes:
          type: integer
        sha256:
          type: string
        format:
          nullable: true
          oneOf:
            - $ref: '#/components/schemas/DocumentFormatEnum'
            - $ref: '#/components/schemas/NullEnum'
      required:
        - filename
        - format
        - mime_type
        - pages
        - sha256
        - size_bytes
    ExtractedFields:
      type: object
      description: >-
        Content read off the document. Every field is best-effort and may be
        null.
      properties:
        doc_type:
          type: string
          nullable: true
        doc_subtype:
          type: string
          nullable: true
        issuer:
          type: string
          nullable: true
        name:
          type: string
          nullable: true
        address:
          type: string
          nullable: true
        document_date:
          type: string
          nullable: true
        account_number:
          type: string
          nullable: true
        currency:
          type: string
          nullable: true
      required:
        - account_number
        - address
        - currency
        - doc_subtype
        - doc_type
        - document_date
        - issuer
        - name
    EngineInfo:
      type: object
      properties:
        version:
          type: string
        mode:
          $ref: '#/components/schemas/ModeEnum'
      required:
        - mode
        - version
    ErrorDetail:
      type: object
      properties:
        type:
          $ref: '#/components/schemas/ErrorTypeEnum'
        code:
          type: string
          description: Machine-readable cause, e.g. `unsupported_document`.
        message:
          type: string
          description: Human-readable explanation. Safe to log; do not parse.
      required:
        - code
        - message
        - type
    FlagCodeEnum:
      enum:
        - ai_generated_metadata
        - ai_generated_embedded_image
        - photoshop_artifact
        - editing_software_detected
        - metadata_scrubbed
        - document_rebuilt
        - incremental_edit
        - empty_shell_revision
        - font_inconsistency
        - numeric_font_mismatch
        - amount_outlier
        - template_deviation
        - visual_tampering
        - fabricated_document
      type: string
      description: |-
        * `ai_generated_metadata` - ai_generated_metadata
        * `ai_generated_embedded_image` - ai_generated_embedded_image
        * `photoshop_artifact` - photoshop_artifact
        * `editing_software_detected` - editing_software_detected
        * `metadata_scrubbed` - metadata_scrubbed
        * `document_rebuilt` - document_rebuilt
        * `incremental_edit` - incremental_edit
        * `empty_shell_revision` - empty_shell_revision
        * `font_inconsistency` - font_inconsistency
        * `numeric_font_mismatch` - numeric_font_mismatch
        * `amount_outlier` - amount_outlier
        * `template_deviation` - template_deviation
        * `visual_tampering` - visual_tampering
        * `fabricated_document` - fabricated_document
    SeverityEnum:
      enum:
        - low
        - medium
        - high
      type: string
      description: |-
        * `low` - low
        * `medium` - medium
        * `high` - high
    FlagReason:
      type: object
      properties:
        code:
          type: string
          description: 'Namespaced reason id. Open set: do not switch on it.'
        summary:
          type: string
        pages:
          type: array
          items:
            type: integer
          description: 1-indexed; empty if file-wide.
        evidence:
          type: object
          additionalProperties: {}
      required:
        - code
        - evidence
        - pages
        - summary
    OutcomeGuidanceEnum:
      enum:
        - ACCEPTED
        - REJECTED
        - PENDING
        - ADVISORY
      type: string
      description: |-
        * `ACCEPTED` - ACCEPTED
        * `REJECTED` - REJECTED
        * `PENDING` - PENDING
        * `ADVISORY` - ADVISORY
    DocumentFormatEnum:
      enum:
        - digital_pdf
        - scanned_pdf
        - image
      type: string
      description: |-
        * `digital_pdf` - digital_pdf
        * `scanned_pdf` - scanned_pdf
        * `image` - image
    ErrorTypeEnum:
      enum:
        - invalid_request_error
        - authentication_error
        - insufficient_credits_error
        - permission_error
        - not_found_error
        - rate_limit_error
        - api_error
      type: string
      description: |-
        * `invalid_request_error` - invalid_request_error
        * `authentication_error` - authentication_error
        * `insufficient_credits_error` - insufficient_credits_error
        * `permission_error` - permission_error
        * `not_found_error` - not_found_error
        * `rate_limit_error` - rate_limit_error
        * `api_error` - api_error
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: bearer
      bearerFormat: API key
      description: >-
        Paste your workspace API key from Settings. Sent as Authorization:
        Bearer <key>.

````