openapi: 3.1.0
info:
  title: ClearStaq Public API
  version: 1.0.0
  summary: Submit bank-statement PDFs and receive structured analysis results.
  description: |
    The ClearStaq public API lets external systems submit bank-statement PDFs
    for parsing + fraud analysis. Results are delivered asynchronously by
    signed webhook to a caller-provided `callback_url`. A polling endpoint
    (`GET /v1/analyses/{id}`) is available for integrations that cannot
    receive inbound webhooks.

    Authentication uses bearer tokens created at
    https://app.clearstaq.com/app/settings/integrations.
servers:
  - url: https://app.clearstaq.com
    description: Production
components:
  securitySchemes:
    BearerApiKey:
      type: http
      scheme: bearer
      bearerFormat: cg_live_*
  schemas:
    AnalysisQueued:
      type: object
      required: [id, status, created_at]
      properties:
        id:
          type: string
          description: Analysis identifier. Use it to poll or correlate with a webhook payload.
        status:
          type: string
          enum: [queued]
        client_ref:
          type: string
          nullable: true
        callback_id:
          type: string
        created_at:
          type: string
          format: date-time
    WebhookEnvelope:
      type: object
      required: [id, event, status, created_at]
      properties:
        id:
          type: string
        event:
          type: string
          enum: [analysis.completed, analysis.failed]
        client_ref:
          type: string
          nullable: true
        status:
          type: string
          enum: [completed, failed]
        created_at:
          type: string
          format: date-time
        completed_at:
          type: string
          format: date-time
          nullable: true
        metadata:
          type: object
          additionalProperties: true
        result:
          $ref: "#/components/schemas/AnalysisResult"
        error:
          $ref: "#/components/schemas/AnalysisError"
    AnalysisResult:
      type: object
      nullable: true
      properties:
        bank_name: { type: string, nullable: true }
        account_holder_name: { type: string, nullable: true }
        account_number_last4: { type: string, nullable: true }
        currency: { type: string, nullable: true }
        period_start: { type: string, format: date, nullable: true }
        period_end: { type: string, format: date, nullable: true }
        starting_balance: { type: number, nullable: true }
        ending_balance: { type: number, nullable: true }
        average_balance: { type: number, nullable: true }
        total_deposits: { type: number, nullable: true }
        total_withdrawals: { type: number, nullable: true }
        true_revenue: { type: number, nullable: true }
        estimated_monthly_revenue: { type: number, nullable: true }
        number_of_deposits: { type: integer, nullable: true }
        number_of_withdrawals: { type: integer, nullable: true }
        number_of_nsf: { type: integer, nullable: true }
        number_of_negative_days: { type: integer, nullable: true }
        fraud_score: { type: integer, nullable: true }
        fraud_risk_level: { type: string, nullable: true }
        monthly_summary: { type: array, items: { type: object } }
        debt_outflows: { type: array, items: { type: object } }
        transactions:
          type: array
          items:
            type: object
            properties:
              date: { type: string, format: date, nullable: true }
              description: { type: string, nullable: true }
              amount: { type: number, nullable: true }
              type: { type: string, nullable: true }
              category: { type: string, nullable: true }
              running_balance: { type: number, nullable: true }
              flagged: { type: boolean, nullable: true }
    AnalysisError:
      type: object
      nullable: true
      properties:
        code: { type: string }
        message: { type: string }
    ErrorResponse:
      type: object
      properties:
        error:
          type: object
          required: [code, message]
          properties:
            code: { type: string }
            message: { type: string }
security:
  - BearerApiKey: []
paths:
  /api/v1/analyses:
    post:
      summary: Submit a bank statement for analysis
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [file]
              properties:
                file:
                  type: string
                  format: binary
                  description: PDF file, up to 25MB.
                callback_url:
                  type: string
                  format: uri
                  description: HTTPS URL that will receive the signed webhook payload when the analysis completes.
                client_ref:
                  type: string
                  description: Free-form reference stored on the callback and echoed back in the webhook payload.
                metadata:
                  type: string
                  description: JSON-encoded object; passed through unchanged to the webhook payload.
      responses:
        "202":
          description: Accepted for processing.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AnalysisQueued"
        "401": { description: Invalid or missing API key, content: { application/json: { schema: { $ref: "#/components/schemas/ErrorResponse" } } } }
        "402": { description: Plan excluded or insufficient credits, content: { application/json: { schema: { $ref: "#/components/schemas/ErrorResponse" } } } }
        "413": { description: File too large (>25MB) }
        "415": { description: Only application/pdf is accepted }
        "422": { description: Validation failed, content: { application/json: { schema: { $ref: "#/components/schemas/ErrorResponse" } } } }
        "502": { description: Parser unavailable }
  /api/v1/analyses/{id}:
    get:
      summary: Fetch analysis status or completed result
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: string }
      responses:
        "200":
          description: Analysis envelope or status snapshot.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookEnvelope"
        "404": { description: Analysis not found for this API key }
  /api/v1/webhooks/test:
    post:
      summary: Send a signed test webhook to a URL
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [callback_url]
              properties:
                callback_url:
                  type: string
                  format: uri
      responses:
        "200":
          description: Delivered (or receiver responded).
          content:
            application/json:
              schema:
                type: object
                properties:
                  delivered: { type: boolean }
                  status: { type: integer, nullable: true }
                  signature: { type: string }
webhooks:
  analysisCompleted:
    post:
      summary: ClearStaq -> your server on analysis completion
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WebhookEnvelope"
      responses:
        "2XX":
          description: Receipt acknowledged. Any non-2xx response triggers retry with exponential backoff.
