openapi: 3.1.0
info:
  title: AgentForms Agent API
  version: "2.0.0"
  description: |
    Programmatic form lifecycle for AI agents and integrations.

    All routes return JSON. Authentication via API key in the Authorization header:
    ```
    Authorization: Bearer afk_live_...
    ```

    Base URL: `https://agentforms.io/api/v2`

    Permissions model:
    - `read_forms` — list and view forms, versions, analytics
    - `write_forms` — create forms, update fields, create API keys
    - `read_submissions` — view submissions and analytics
    - `delete_forms` — delete forms, revoke API keys

    Tier-gated features:
    - Free: Basic form CRUD, submissions, analytics
    - Starter+: AI form builder, geo/device analytics
    - Pro+: Impressions, conversion analytics

    Field types: `text`, `email`, `tel`, `textarea`, `select`, `number`, `date`, `hidden`

paths:
  /keys:
    get:
      operationId: listKeys
      summary: List all API keys
      security:
        - BearerAuth: []
      responses:
        "200":
          description: List of API keys
          content:
            application/json:
              schema:
                type: object
                properties:
                  keys:
                    type: array
                    items:
                      $ref: '#/components/schemas/ApiKey'
    post:
      operationId: createKey
      summary: Create a new API key
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
                  description: Human-readable key name
                permissions:
                  type: object
                  description: Granular permissions (optional)
                  additionalProperties:
                    type: boolean
      responses:
        "201":
          description: New API key created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id: { type: integer }
                  key_prefix: { type: string }
                  full_key: { type: string }
                  name: { type: string }
                  permissions: { type: object, nullable: true }
                  created_at: { type: string, nullable: true }
                  warning: { type: string }

  /keys/{key_id}:
    delete:
      operationId: revokeKey
      summary: Revoke an API key
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: key_id
          required: true
          schema: { type: integer }
      responses:
        "200":
          description: Key revoked
          content:
            application/json:
              schema:
                type: object
                properties:
                  revoked: { type: boolean }
                  id: { type: integer }

  /forms:
    get:
      operationId: listForms
      summary: List all forms
      security:
        - BearerAuth: []
      parameters:
        - in: query
          name: limit
          schema: { type: integer, default: 50, maximum: 200 }
        - in: query
          name: offset
          schema: { type: integer, default: 0 }
      responses:
        "200":
          description: Paginated form list
          content:
            application/json:
              schema:
                type: object
                properties:
                  forms:
                    type: array
                    items: { $ref: '#/components/schemas/FormSummary' }
                  total: { type: integer }
                  limit: { type: integer }
                  offset: { type: integer }
    post:
      operationId: createForm
      summary: Create a new form programmatically
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, fields]
              properties:
                name:
                  type: string
                  description: Form display name
                fields:
                  type: array
                  minItems: 1
                  items: { $ref: '#/components/schemas/FieldDefinition' }
                metadata:
                  type: object
                  nullable: true
                  description: Arbitrary JSON metadata (e.g., session context)
      responses:
        "201":
          description: Form created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id: { type: integer }
                  token: { type: string }
                  name: { type: string }
                  fields:
                    type: array
                    items: { $ref: '#/components/schemas/FieldDefinition' }
                  created_by: { type: string, example: "agent" }
                  embed_url: { type: string }
                  submit_url: { type: string }
                  created_at: { type: string }

  /forms/generate:
    post:
      operationId: generateForm
      summary: Generate a form from natural language prompt (AI-powered)
      security:
        - BearerAuth: []
      description: |
        Tier-gated (Starter+). Calls the local LLM to generate field definitions
        from a natural language description.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [prompt]
              properties:
                prompt:
                  type: string
                  minLength: 5
                  description: Natural language description of the form
                form_name:
                  type: string
                  description: Override the generated form name
      responses:
        "201":
          description: AI-generated form created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id: { type: integer }
                  token: { type: string }
                  name: { type: string }
                  fields:
                    type: array
                    items: { $ref: '#/components/schemas/FieldDefinition' }
                  field_count: { type: integer }
                  created_by: { type: string, example: "ai_builder" }
                  warnings:
                    type: array
                    items: { type: string }
                  embed_url: { type: string }
                  submit_url: { type: string }
                  created_at: { type: string }

  /forms/suggestions:
    post:
      operationId: suggestImprovements
      summary: Get AI-powered form improvement suggestions
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [form_token]
              properties:
                form_token:
                  type: string
                context:
                  type: string
                  description: Additional context for suggestions
      responses:
        "200":
          description: Improvement suggestions
          content:
            application/json:
              schema:
                type: object
                properties:
                  form_id: { type: integer }
                  form_token: { type: string }
                  current_field_count: { type: integer }
                  suggestions:
                    type: array
                    items: { type: object }

  /forms/{form_token}:
    get:
      operationId: getForm
      summary: Get form details by token
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: form_token
          required: true
          schema: { type: string }
      responses:
        "200":
          description: Form details
          content:
            application/json:
              schema:
                type: object
                properties:
                  id: { type: integer }
                  token: { type: string }
                  name: { type: string }
                  fields:
                    type: array
                    items: { $ref: '#/components/schemas/FieldDefinition' }
                  field_count: { type: integer }
                  created_by: { type: string }
                  metadata:
                    type: object
                    nullable: true
                  honeypot_enabled: { type: boolean }
                  spam_filter_enabled: { type: boolean }
                  webhook_enabled: { type: boolean }
                  rate_limit_enabled: { type: boolean }
                  embed_url: { type: string }
                  submit_url: { type: string }
                  created_at: { type: string }

    delete:
      operationId: deleteForm
      summary: Delete a form and all submissions
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: form_token
          required: true
          schema: { type: string }
      responses:
        "200":
          description: Form deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  deleted: { type: boolean }
                  id: { type: integer }
                  token: { type: string }

  /forms/{form_token}/fields:
    put:
      operationId: updateFields
      summary: Update form fields (replace all)
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: form_token
          required: true
          schema: { type: string }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [fields]
              properties:
                fields:
                  type: array
                  items: { $ref: '#/components/schemas/FieldDefinition' }
      responses:
        "200":
          description: Fields updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  updated: { type: boolean }
                  fields:
                    type: array
                    items: { $ref: '#/components/schemas/FieldDefinition' }
                  field_count: { type: integer }

  /forms/{form_token}/config:
    get:
      operationId: getFormConfig
      summary: Get public form configuration (no auth required)
      parameters:
        - in: path
          name: form_token
          required: true
          schema: { type: string }
      responses:
        "200":
          description: Public form config for rendering

  /forms/{form_token}/submissions:
    get:
      operationId: listSubmissions
      summary: List submissions for a form
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: form_token
          required: true
          schema: { type: string }
        - in: query
          name: limit
          schema: { type: integer, default: 50, maximum: 200 }
        - in: query
          name: offset
          schema: { type: integer, default: 0 }
      responses:
        "200":
          description: Paginated submissions
          content:
            application/json:
              schema:
                type: object
                properties:
                  submissions:
                    type: array
                    items: { $ref: '#/components/schemas/Submission' }
                  total: { type: integer }
                  limit: { type: integer }
                  offset: { type: integer }

  /forms/{form_token}/submissions/{sub_id}:
    get:
      operationId: getSubmission
      summary: Get a single submission by ID
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: form_token
          required: true
          schema: { type: string }
        - in: path
          name: sub_id
          required: true
          schema: { type: integer }
      responses:
        "200":
          description: Single submission
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Submission' }

  /forms/{form_token}/analytics:
    get:
      operationId: getAnalytics
      summary: Get form analytics (tier-gated)
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: form_token
          required: true
          schema: { type: string }
        - in: query
          name: days
          schema: { type: integer, default: 30, maximum: 90 }
      responses:
        "200":
          description: Analytics data
          content:
            application/json:
              schema:
                type: object
                properties:
                  form_id: { type: integer }
                  form_token: { type: string }
                  tier: { type: string }
                  analytics_level: { type: string }
                  days: { type: integer }
                  daily_submissions:
                    type: array
                    items: { type: object }
                  summary: { type: object }
                  geo:
                    type: array
                    nullable: true
                  device:
                    type: array
                    nullable: true
                  impressions:
                    type: array
                    nullable: true

  /forms/{form_token}/versions:
    get:
      operationId: listVersions
      summary: List version history
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: form_token
          required: true
          schema: { type: string }
      responses:
        "200":
          description: Version history

  /forms/{form_token}/versions/{version_id}:
    get:
      operationId: getVersion
      summary: Get specific version
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: form_token
          required: true
          schema: { type: string }
        - in: path
          name: version_id
          required: true
          schema: { type: integer }
      responses:
        "200":
          description: Version details

  /forms/{form_token}/versions/{version_id}/rollback:
    post:
      operationId: rollbackVersion
      summary: Roll back to a previous version
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: form_token
          required: true
          schema: { type: string }
        - in: path
          name: version_id
          required: true
          schema: { type: integer }
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  type: string

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: afk_live

  schemas:
    ApiKey:
      type: object
      properties:
        id: { type: integer }
        key_prefix: { type: string }
        name: { type: string }
        permissions:
          type: object
          nullable: true
        created_at: { type: string }
        revoked: { type: boolean }

    FormSummary:
      type: object
      properties:
        id: { type: integer }
        token: { type: string }
        name: { type: string }
        field_count: { type: integer }
        created_by: { type: string }
        created_at: { type: string }

    FieldDefinition:
      type: object
      required: [name, label, type]
      properties:
        name:
          type: string
          description: Snake-case field identifier
        label:
          type: string
          description: Human-readable display label
        type:
          type: string
          enum: [text, email, tel, textarea, select, number, date, hidden]
        required:
          type: boolean
          default: false
        options:
          type: array
          items: { type: string }
          description: Options for select type
        placeholder:
          type: string
        default:
          type: string

    Submission:
      type: object
      properties:
        id: { type: integer }
        site_id: { type: integer }
        submitted_at: { type: string }
        data:
          type: string
          description: Raw JSON string of field data
        dynamic_data:
          type: object
          description: Parsed field data (added by SDK)
        client_ip: { type: string }
        user_agent: { type: string }

    WebhookPayload:
      type: object
      description: Payload delivered to webhook on form submission
      properties:
        event:
          type: string
          example: submission
        site_id: { type: integer }
        site_name: { type: string }
        submission_id: { type: integer }
        submitted_at: { type: string }
        fields:
          type: object
          additionalProperties: { type: string }
        field_metadata:
          type: object
          nullable: true
          properties:
            visible_fields: { type: object }
            computed_fields: { type: object }
            applied_conditions:
              type: array
              items: { type: object }