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

# Create workflow



## OpenAPI

````yaml /openapi.json post /v1/workflows
openapi: 3.1.0
info:
  title: Factify API
  version: 1.1.1
  description: >-
    Factify API enables organizations to ingest records, manage workflows, and
    extract auditable facts.


    ## Authentication


    Bearer authentication header of the form `Bearer <token>`, where `<token>`
    is your auth token.


    ```

    Authorization: Bearer ffy_prod_<base32_uuid><base62_random>

    ```


    ## Rate Limiting


    Per-API-key rate limits apply. Concrete thresholds are configured per

    deployment and surface via standard `Retry-After` and `RateLimit-*`

    response headers when a request is throttled.


    ## Errors


    Factify uses conventional HTTP status codes and returns structured error
    responses following [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457)
    (Problem Details for HTTP APIs).
  contact:
    name: Factify API Support
    email: api@factify.com
    url: https://factify.com/support
  license:
    name: Proprietary
    url: https://factify.com/terms
servers:
  - url: https://api.factify.com
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Organizations
    description: Organizations and their settings.
  - name: Members
    description: Membership roster and roles within an organization.
  - name: Invitations
    description: Pending invitations to join an organization.
  - name: Users
    description: The authenticated user's profile.
  - name: ApiKeys
    description: API keys used to authenticate SDK and integration callers.
  - name: Usage
    description: |
      Per-organization usage and quota limits. Future operations covering
      API-key-level quotas and usage history land here too.
  - name: Connections
    description: Inbound integration connections that records are ingested from.
  - name: Workflows
    description: Workflow templates that define the rubric set for fact extraction.
  - name: Plans
    description: Workflow instances — bind claims and lock to produce an extraction spec.
  - name: Records
    description: Generic JSON records ingested for claim extraction.
  - name: Audit
    description: Unified audit and provenance events.
  - name: Notifications
    description: In-app notification feed backed by audit events and per-user read state.
  - name: Internal
    description: Internal callbacks not intended for public SDK consumers.
  - name: RubricContentions
    description: >-
      Rubric contention detection and resolution — surface and resolve competing
      claim bindings.
  - name: IdentityProviders
    description: Per-organization SAML identity providers for SSO.
  - name: Analytics
    description: >-
      Org-scoped execution analytics — volume, decision breakdown, and latency
      over plan executions.
  - name: Auth
    description: |
      Browser-facing authentication surface — CSRF, session, OAuth callback,
      OTP, passkey, and refresh-token endpoints. These predate factapi's
      versioned `/v1/*` SDK surface and use the BetterAuth wire format the
      workspace SPA already speaks; SDK generators skip them via
      `x-speakeasy-ignore`.
paths:
  /v1/workflows:
    post:
      tags:
        - Workflows
      summary: Create workflow
      operationId: createWorkflow
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWorkflowBody'
      responses:
        '201':
          description: Workflow created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Workflow'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'
components:
  schemas:
    CreateWorkflowBody:
      type: object
      required:
        - name
        - rubrics
      additionalProperties: false
      properties:
        name:
          type: string
          description: Human-readable workflow name.
          example: Employment Agreement Extraction
        description:
          type: string
          description: Human-readable workflow description.
          default: ''
        body_md:
          type: string
          description: Markdown template body with `{{slot_name}}` placeholders.
          default: ''
        rubrics:
          type: array
          description: Claim slot definitions to create with this workflow.
          items:
            $ref: '#/components/schemas/CreateRubricBody'
    Workflow:
      type: object
      required:
        - id
        - name
        - description
        - body_md
        - rubrics
        - created_at
      additionalProperties: false
      properties:
        id:
          type: string
          description: Workflow TypeID (wfl_…)
          example: wfl_01j9z0000000000000000000a0
        name:
          type: string
          description: Human-readable workflow name.
        description:
          type: string
          description: Human-readable workflow description. Empty string when unset.
        active_revision_id:
          type: string
          nullable: true
          description: |
            TypeID (wrev_…) of the workflow's currently active revision. Null
            when no revision is active (draft-only, never activated).
        body_md:
          type: string
          description: >-
            Markdown template body. Claim slot placeholders use `{{slot_name}}`
            syntax.
        rubrics:
          type: array
          description: Claim slot definitions for this workflow, in creation order.
          items:
            $ref: '#/components/schemas/Rubric'
        created_at:
          type: string
          format: date-time
    CreateRubricBody:
      type: object
      required:
        - slot_name
        - label
        - data_type
      additionalProperties: false
      properties:
        slot_name:
          type: string
          description: Unique slot identifier within this workflow.
          example: party_name
        label:
          type: string
          example: Party Name
        data_type:
          type: string
          example: text
        validation_rule:
          type: string
          example: non empty strings without any numbers
          default: ''
        object_schema:
          type: string
          description: JSON Schema for an object data_type slot; empty otherwise.
          default: ''
        sources:
          type: array
          items:
            $ref: '#/components/schemas/RubricSource'
          description: >-
            Where the slot's value comes from; empty == implicit claim
            extraction.
        description:
          type: string
          default: ''
        extraction_hint:
          type: string
          description: >
            Extraction-focused guidance for the matching model. When set, this
            overrides description for Pass A matching and rubric embedding. When
            omitted, description is used as the fallback.
        binding_scope:
          $ref: '#/components/schemas/RubricBindingScope'
          default: plan
          description: Defaults to `plan` when omitted.
        required:
          type: boolean
          description: |
            Static classifier required/optional flag for completeness gates.
    Rubric:
      type: object
      required:
        - id
        - slot_name
        - label
        - data_type
        - binding_scope
        - created_at
      additionalProperties: false
      properties:
        id:
          type: string
          description: Rubric TypeID (rub_…)
        slot_name:
          type: string
          description: >-
            Unique slot name within the workflow. Used to match `{{slot_name}}`
            placeholders in body_md.
          example: party_name
        label:
          type: string
          description: Display label for the slot.
        data_type:
          type: string
          description: >-
            Expected data type of the extracted value (e.g. "text", "date",
            "number").
          example: text
        validation_rule:
          type: string
          description: Optional validation expression applied to extracted values.
        object_schema:
          type: string
          description: JSON Schema for an object data_type slot; empty otherwise.
        sources:
          type: array
          items:
            $ref: '#/components/schemas/RubricSource'
          description: >-
            Where the slot's value comes from; empty == implicit claim
            extraction.
        description:
          type: string
          description: >-
            Human-readable description shown in the Workflow Room. Use
            extraction_hint for LLM-facing guidance.
        extraction_hint:
          type: string
          description: |
            Extraction-focused guidance. Null when not set by the creator.
          nullable: true
        binding_scope:
          $ref: '#/components/schemas/RubricBindingScope'
        required:
          type: boolean
          description: |
            Static classifier required/optional flag for completeness gates.
            When true, the slot must be bound before the plan is complete
            (subject to required_when gating when that predicate is set).
          default: false
        created_at:
          type: string
          format: date-time
    ErrorModel:
      additionalProperties: false
      type: object
      properties:
        detail:
          type: string
          description: >-
            A human-readable explanation specific to this occurrence of the
            problem.
          example: Property foo is required but is missing.
        errors:
          description: Optional list of individual error details
          type: array
          items:
            $ref: '#/components/schemas/ErrorDetail'
        instance:
          type: string
          format: uri
          description: >-
            A URI reference that identifies the specific occurrence of the
            problem.
          example: https://example.com/error-log/abc123
        status:
          type: integer
          format: int64
          description: HTTP status code
          example: 400
        title:
          type: string
          description: >-
            A short, human-readable summary of the problem type. This value
            should not change between occurrences of the error.
          example: Bad Request
        type:
          type: string
          format: uri
          default: about:blank
          description: A URI reference to human-readable documentation for the error.
          example: https://example.com/errors/example
    RubricSource:
      type: object
      description: One candidate producer for a rubric slot (ENG-6227 policy chaining).
      required:
        - source_type
      properties:
        source_type:
          type: string
          enum:
            - claim
            - workflow
            - operator
          description: |
            claim — extraction-derived; workflow — chained from an upstream
            workflow's outcome; operator — exclusively operator-declared
            (via bind_fact/case UI), never a CLW Pass A/B extraction or
            contention target (ENG-7014).
        source_workflow_id:
          type: string
          description: >-
            Upstream workflow id; required for a workflow source, omitted for a
            claim source.
    RubricBindingScope:
      type: string
      enum:
        - workflow
        - plan
      description: >
        Controls whether the rubric's claim binding is shared workflow-wide
        (workflow)

        or is per-plan.
          workflow — the claim is bound once at the workflow level and snapshotted
            into each new plan on open. OpenPlan rejects if any workflow-scoped
            rubric has no workflow-wide binding.
          plan — the claim is bound independently for each plan (default).
    ErrorDetail:
      additionalProperties: false
      type: object
      properties:
        location:
          type: string
          description: >-
            Where the error occurred, e.g. 'body.items[3].tags' or
            'path.thing-id'
        message:
          type: string
          description: Error message text
        value:
          description: The value at the given location
  responses:
    BadRequest:
      description: Bad Request
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ErrorModel'
          example:
            type: about:blank
            title: Bad Request
            status: 400
            detail: Request body is malformed or missing required fields.
    Unauthorized:
      description: Unauthorized
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ErrorModel'
          example:
            type: about:blank
            title: Unauthorized
            status: 401
            detail: Missing or invalid authentication credentials.
    Forbidden:
      description: Forbidden
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ErrorModel'
          example:
            type: about:blank
            title: Forbidden
            status: 403
            detail: >-
              You do not have permission to perform this action on this
              resource.
    UnprocessableEntity:
      description: Unprocessable Entity
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ErrorModel'
          example:
            type: about:blank
            title: Unprocessable Entity
            status: 422
            detail: Request body failed validation.
            errors:
              - location: body.email
                message: expected string to match format 'email'
                value: not-an-email
    TooManyRequests:
      description: Too Many Requests
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ErrorModel'
          example:
            type: about:blank
            title: Too Many Requests
            status: 429
            detail: >-
              Rate limit exceeded. Retry after the period indicated by the
              Retry-After header.
    InternalServerError:
      description: Internal Server Error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ErrorModel'
          example:
            type: about:blank
            title: Internal Server Error
            status: 500
            detail: >-
              An unexpected error occurred. Retry, and contact support if the
              issue persists.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API Key
      description: |
        Bearer authentication using a factapi-issued API key
        (`ffy_<env>_<base32_uuid><base62_random>`). Cookie-based
        sessions are accepted automatically by user-facing endpoints
        but are not surfaced as an OpenAPI auth scheme.

````