openapi: 3.0.4
info:
  title: BootForm API
  description: Combined REST surface across BootForm's Submission API (public form intake) and Dashboard API (forms/submissions/destinations/account management) - api-spec.md documents both as one logical API.
  version: v1
paths:
  '/{formIdOrSlug}':
    post:
      tags:
        - Submissions
      parameters:
        - name: formIdOrSlug
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
  /workspaces:
    get:
      tags:
        - Workspaces
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/WorkspaceListResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspaceListResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/WorkspaceListResponse'
    post:
      tags:
        - Workspaces
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWorkspaceRequest'
          text/json:
            schema:
              $ref: '#/components/schemas/CreateWorkspaceRequest'
          application/*+json:
            schema:
              $ref: '#/components/schemas/CreateWorkspaceRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/WorkspaceDetailResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspaceDetailResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/WorkspaceDetailResponse'
  '/workspaces/{workspaceId}':
    patch:
      tags:
        - Workspaces
      parameters:
        - name: workspaceId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateWorkspaceRequest'
          text/json:
            schema:
              $ref: '#/components/schemas/UpdateWorkspaceRequest'
          application/*+json:
            schema:
              $ref: '#/components/schemas/UpdateWorkspaceRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/WorkspaceDetailResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspaceDetailResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/WorkspaceDetailResponse'
    delete:
      tags:
        - Workspaces
      parameters:
        - name: workspaceId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/DeleteWorkspaceResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteWorkspaceResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/DeleteWorkspaceResponse'
  /account/verified-emails:
    get:
      tags:
        - VerifiedEmails
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/VerifiedEmailListResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/VerifiedEmailListResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/VerifiedEmailListResponse'
    post:
      tags:
        - VerifiedEmails
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateVerifiedEmailRequest'
          text/json:
            schema:
              $ref: '#/components/schemas/CreateVerifiedEmailRequest'
          application/*+json:
            schema:
              $ref: '#/components/schemas/CreateVerifiedEmailRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/VerifiedEmailDetailResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/VerifiedEmailDetailResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/VerifiedEmailDetailResponse'
  '/account/verified-emails/{id}/resend':
    post:
      tags:
        - VerifiedEmails
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/VerifiedEmailDetailResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/VerifiedEmailDetailResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/VerifiedEmailDetailResponse'
  '/account/verified-emails/{id}':
    delete:
      tags:
        - VerifiedEmails
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/DeleteVerifiedEmailResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteVerifiedEmailResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/DeleteVerifiedEmailResponse'
  '/account/verified-emails/verify/{token}':
    get:
      tags:
        - VerifiedEmails
      parameters:
        - name: token
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/VerifyEmailResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/VerifyEmailResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/VerifyEmailResponse'
  '/forms/{formId}/submissions':
    get:
      tags:
        - Submissions
      parameters:
        - name: formId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: page
          in: query
          schema:
            type: integer
            format: int32
            default: 1
        - name: per_page
          in: query
          schema:
            type: integer
            format: int32
            default: 50
        - name: q
          in: query
          schema:
            type: string
            default: 
        - name: spam
          in: query
          schema:
            type: boolean
            default: false
        - name: archived
          in: query
          schema:
            type: boolean
            default: false
        - name: starred
          in: query
          schema:
            type: boolean
            default: 
        - name: since
          in: query
          schema:
            type: string
            format: date-time
            default: 
        - name: until
          in: query
          schema:
            type: string
            format: date-time
            default: 
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/SubmissionListResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/SubmissionListResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/SubmissionListResponse'
  '/forms/{formId}/submissions/stats':
    get:
      tags:
        - Submissions
      parameters:
        - name: formId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: since
          in: query
          schema:
            type: string
            format: date-time
            default: 
        - name: until
          in: query
          schema:
            type: string
            format: date-time
            default: 
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/SubmissionStatsResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/SubmissionStatsResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/SubmissionStatsResponse'
  '/forms/{formId}/submissions/{submissionId}':
    get:
      tags:
        - Submissions
      parameters:
        - name: formId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: submissionId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/SubmissionDetailResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/SubmissionDetailResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/SubmissionDetailResponse'
    patch:
      tags:
        - Submissions
      parameters:
        - name: formId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: submissionId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSubmissionRequest'
          text/json:
            schema:
              $ref: '#/components/schemas/UpdateSubmissionRequest'
          application/*+json:
            schema:
              $ref: '#/components/schemas/UpdateSubmissionRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/SubmissionDetailResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/SubmissionDetailResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/SubmissionDetailResponse'
    delete:
      tags:
        - Submissions
      parameters:
        - name: formId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: submissionId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/DeleteSubmissionResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteSubmissionResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/DeleteSubmissionResponse'
  '/forms/{formId}/destinations':
    get:
      tags:
        - NotificationDestinations
      parameters:
        - name: formId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/NotificationDestinationListResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationDestinationListResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/NotificationDestinationListResponse'
    post:
      tags:
        - NotificationDestinations
      parameters:
        - name: formId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateNotificationDestinationRequest'
          text/json:
            schema:
              $ref: '#/components/schemas/CreateNotificationDestinationRequest'
          application/*+json:
            schema:
              $ref: '#/components/schemas/CreateNotificationDestinationRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/NotificationDestinationDetailResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationDestinationDetailResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/NotificationDestinationDetailResponse'
  '/forms/{formId}/destinations/{destinationId}':
    patch:
      tags:
        - NotificationDestinations
      parameters:
        - name: formId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: destinationId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateNotificationDestinationRequest'
          text/json:
            schema:
              $ref: '#/components/schemas/UpdateNotificationDestinationRequest'
          application/*+json:
            schema:
              $ref: '#/components/schemas/UpdateNotificationDestinationRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/NotificationDestinationDetailResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationDestinationDetailResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/NotificationDestinationDetailResponse'
    delete:
      tags:
        - NotificationDestinations
      parameters:
        - name: formId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: destinationId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/DeleteNotificationDestinationResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteNotificationDestinationResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/DeleteNotificationDestinationResponse'
  '/forms/{formId}/destinations/{destinationId}/rotate-secret':
    post:
      tags:
        - NotificationDestinations
      parameters:
        - name: formId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: destinationId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/RotateWebhookSecretResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/RotateWebhookSecretResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/RotateWebhookSecretResponse'
  /forms:
    get:
      tags:
        - Forms
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            format: int32
            default: 1
        - name: per_page
          in: query
          schema:
            type: integer
            format: int32
            default: 50
        - name: workspace_id
          in: query
          schema:
            type: string
            format: uuid
            default: 
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/FormListResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/FormListResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/FormListResponse'
    post:
      tags:
        - Forms
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateFormRequest'
          text/json:
            schema:
              $ref: '#/components/schemas/CreateFormRequest'
          application/*+json:
            schema:
              $ref: '#/components/schemas/CreateFormRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/FormDetailResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/FormDetailResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/FormDetailResponse'
  '/forms/{formId}':
    get:
      tags:
        - Forms
      parameters:
        - name: formId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/FormDetailResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/FormDetailResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/FormDetailResponse'
    patch:
      tags:
        - Forms
      parameters:
        - name: formId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateFormRequest'
          text/json:
            schema:
              $ref: '#/components/schemas/UpdateFormRequest'
          application/*+json:
            schema:
              $ref: '#/components/schemas/UpdateFormRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/FormDetailResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/FormDetailResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/FormDetailResponse'
    delete:
      tags:
        - Forms
      parameters:
        - name: formId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/DeleteFormResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteFormResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/DeleteFormResponse'
  '/forms/{formId}/captcha':
    put:
      tags:
        - Forms
      parameters:
        - name: formId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SetCaptchaRequest'
          text/json:
            schema:
              $ref: '#/components/schemas/SetCaptchaRequest'
          application/*+json:
            schema:
              $ref: '#/components/schemas/SetCaptchaRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/FormDetailResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/FormDetailResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/FormDetailResponse'
    delete:
      tags:
        - Forms
      parameters:
        - name: formId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/FormDetailResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/FormDetailResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/FormDetailResponse'
  '/claim/{formId}/preview':
    get:
      tags:
        - Claim
      parameters:
        - name: formId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/ClaimPreviewResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/ClaimPreviewResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/ClaimPreviewResponse'
  '/claim/{formId}':
    post:
      tags:
        - Claim
      parameters:
        - name: formId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/ClaimFormResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/ClaimFormResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/ClaimFormResponse'
  /auth/register:
    post:
      tags:
        - Auth
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RegisterRequest'
          text/json:
            schema:
              $ref: '#/components/schemas/RegisterRequest'
          application/*+json:
            schema:
              $ref: '#/components/schemas/RegisterRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/AuthResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/AuthResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/AuthResponse'
  /auth/login:
    post:
      tags:
        - Auth
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LoginRequest'
          text/json:
            schema:
              $ref: '#/components/schemas/LoginRequest'
          application/*+json:
            schema:
              $ref: '#/components/schemas/LoginRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/AuthResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/AuthResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/AuthResponse'
  /auth/refresh:
    post:
      tags:
        - Auth
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RefreshRequest'
          text/json:
            schema:
              $ref: '#/components/schemas/RefreshRequest'
          application/*+json:
            schema:
              $ref: '#/components/schemas/RefreshRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/AuthResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/AuthResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/AuthResponse'
  /auth/logout:
    post:
      tags:
        - Auth
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RefreshRequest'
          text/json:
            schema:
              $ref: '#/components/schemas/RefreshRequest'
          application/*+json:
            schema:
              $ref: '#/components/schemas/RefreshRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/OkResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/OkResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/OkResponse'
  /auth/magic-link:
    post:
      tags:
        - Auth
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MagicLinkRequest'
          text/json:
            schema:
              $ref: '#/components/schemas/MagicLinkRequest'
          application/*+json:
            schema:
              $ref: '#/components/schemas/MagicLinkRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/OkResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/OkResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/OkResponse'
  '/auth/magic-link/{token}':
    get:
      tags:
        - Auth
      parameters:
        - name: token
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/AuthResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/AuthResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/AuthResponse'
  '/auth/oauth/{provider}':
    get:
      tags:
        - Auth
      parameters:
        - name: provider
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
  '/auth/oauth/{provider}/callback':
    get:
      tags:
        - Auth
      parameters:
        - name: provider
          in: path
          required: true
          schema:
            type: string
        - name: code
          in: query
          schema:
            type: string
        - name: state
          in: query
          schema:
            type: string
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/AuthResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/AuthResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/AuthResponse'
  /account/stats:
    get:
      tags:
        - AccountStats
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/AccountStatsResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/AccountStatsResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/AccountStatsResponse'
  /account:
    get:
      tags:
        - Account
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/AccountResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/AccountResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/AccountResponse'
  /account/api-keys:
    get:
      tags:
        - ApiKeys
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/ApiKeyListResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/ApiKeyListResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/ApiKeyListResponse'
    post:
      tags:
        - ApiKeys
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateApiKeyRequest'
          text/json:
            schema:
              $ref: '#/components/schemas/CreateApiKeyRequest'
          application/*+json:
            schema:
              $ref: '#/components/schemas/CreateApiKeyRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/ApiKeyCreatedResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/ApiKeyCreatedResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/ApiKeyCreatedResponse'
  '/account/api-keys/{keyId}':
    delete:
      tags:
        - ApiKeys
      parameters:
        - name: keyId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: OK
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/RevokeApiKeyResponse'
            application/json:
              schema:
                $ref: '#/components/schemas/RevokeApiKeyResponse'
            text/json:
              schema:
                $ref: '#/components/schemas/RevokeApiKeyResponse'
components:
  schemas:
    AccountDetails:
      required:
        - email
        - plan
      type: object
      properties:
        id:
          type: string
          format: uuid
        email:
          type: string
        name:
          type: string
          nullable: true
        avatar_url:
          type: string
          nullable: true
        oauth_provider:
          type: string
          nullable: true
        plan:
          type: string
        plan_expires_at:
          type: string
          format: date-time
          nullable: true
        monthly_usage:
          type: integer
          format: int32
        monthly_quota:
          type: integer
          format: int32
        created_at:
          type: string
          format: date-time
    AccountResponse:
      required:
        - account
      type: object
      properties:
        ok:
          type: boolean
        account:
          $ref: '#/components/schemas/AccountDetails'
    AccountStatsResponse:
      required:
        - delivery_status
      type: object
      properties:
        ok:
          type: boolean
        total_submissions:
          type: integer
          format: int32
        submissions_last_30_days:
          type: integer
          format: int32
        spam_blocked_last_30_days:
          type: integer
          format: int32
        delivery_status:
          $ref: '#/components/schemas/DeliveryStatusResponse'
        country_breakdown:
          type: array
          items:
            $ref: '#/components/schemas/CountryBreakdownEntry'
    ApiKeyCreated:
      type: object
      properties:
        id:
          type: string
          format: uuid
        label:
          type: string
        key:
          type: string
        key_prefix:
          type: string
        created_at:
          type: string
          format: date-time
    ApiKeyCreatedResponse:
      required:
        - api_key
      type: object
      properties:
        ok:
          type: boolean
        api_key:
          $ref: '#/components/schemas/ApiKeyCreated'
        warning:
          type: string
    ApiKeyListResponse:
      type: object
      properties:
        ok:
          type: boolean
        api_keys:
          type: array
          items:
            $ref: '#/components/schemas/ApiKeySummary'
    ApiKeySummary:
      type: object
      properties:
        id:
          type: string
          format: uuid
        label:
          type: string
        key_prefix:
          type: string
        last_used_at:
          type: string
          format: date-time
          nullable: true
        created_at:
          type: string
          format: date-time
        revoked_at:
          type: string
          format: date-time
          nullable: true
    AuthResponse:
      type: object
      properties:
        ok:
          type: boolean
        access_token:
          type: string
        expires_in:
          type: integer
          format: int32
        refresh_token:
          type: string
    CaptchaResponse:
      type: object
      properties:
        provider:
          type: string
        site_key:
          type: string
      nullable: true
    ClaimFormResponse:
      required:
        - form_id
        - name
      type: object
      properties:
        ok:
          type: boolean
        form_id:
          type: string
          format: uuid
        name:
          type: string
    ClaimPreviewResponse:
      required:
        - form_id
        - held_count
        - preview
      type: object
      properties:
        ok:
          type: boolean
        form_id:
          type: string
        held_count:
          type: integer
          format: int32
        preview:
          type: array
          items:
            $ref: '#/components/schemas/HeldSubmissionPreview'
    CountryBreakdownEntry:
      type: object
      properties:
        country:
          type: string
          nullable: true
        count:
          type: integer
          format: int32
    CreateApiKeyRequest:
      required:
        - label
      type: object
      properties:
        label:
          maxLength: 100
          type: string
    CreateFormRequest:
      required:
        - name
      type: object
      properties:
        name:
          maxLength: 200
          type: string
        redirect_url:
          maxLength: 2048
          type: string
          nullable: true
        allowed_origins:
          type: array
          items:
            type: string
          nullable: true
        subject_template:
          maxLength: 500
          type: string
          nullable: true
        slug:
          maxLength: 100
          type: string
          nullable: true
        workspace_id:
          type: string
          format: uuid
          nullable: true
    CreateNotificationDestinationRequest:
      required:
        - type
        - config
      type: object
      properties:
        type:
          maxLength: 20
          type: string
        config:
          $ref: '#/components/schemas/JsonElement'
    CreateVerifiedEmailRequest:
      required:
        - email
      type: object
      properties:
        email:
          maxLength: 320
          pattern: '^[^\s@]+@[^\s@]+\.[^\s@]+$'
          type: string
    CreateWorkspaceRequest:
      required:
        - name
      type: object
      properties:
        name:
          maxLength: 200
          type: string
        time_zone:
          maxLength: 64
          type: string
          nullable: true
    DailyCountResponse:
      type: object
      properties:
        date:
          type: string
        count:
          type: integer
          format: int32
    DeleteFormResponse:
      type: object
      properties:
        ok:
          type: boolean
        deleted:
          type: boolean
    DeleteNotificationDestinationResponse:
      type: object
      properties:
        ok:
          type: boolean
        deleted:
          type: boolean
    DeleteSubmissionResponse:
      type: object
      properties:
        ok:
          type: boolean
        deleted:
          type: boolean
    DeleteVerifiedEmailResponse:
      type: object
      properties:
        ok:
          type: boolean
        deleted:
          type: boolean
    DeleteWorkspaceResponse:
      type: object
      properties:
        ok:
          type: boolean
        deleted:
          type: boolean
        forms_reassigned_to:
          type: string
          format: uuid
    DeliveryStatusResponse:
      type: object
      properties:
        success:
          type: integer
          format: int32
        error:
          type: integer
          format: int32
        pending:
          type: integer
          format: int32
    FieldRuleRequest:
      required:
        - field
      type: object
      properties:
        field:
          type: string
        required:
          type: boolean
        type:
          type: string
          nullable: true
        min:
          type: number
          format: double
          nullable: true
        max:
          type: number
          format: double
          nullable: true
        min_length:
          type: integer
          format: int32
          nullable: true
        max_length:
          type: integer
          format: int32
          nullable: true
        accepted_mime_types:
          type: array
          items:
            type: string
          nullable: true
        require_work_email:
          type: boolean
    FieldRuleResponse:
      type: object
      properties:
        field:
          type: string
        required:
          type: boolean
        type:
          type: string
          nullable: true
        min:
          type: number
          format: double
          nullable: true
        max:
          type: number
          format: double
          nullable: true
        min_length:
          type: integer
          format: int32
          nullable: true
        max_length:
          type: integer
          format: int32
          nullable: true
        accepted_mime_types:
          type: array
          items:
            type: string
          nullable: true
        require_work_email:
          type: boolean
    FormDetail:
      type: object
      properties:
        id:
          type: string
          format: uuid
        workspace_id:
          type: string
          format: uuid
          nullable: true
        name:
          type: string
        enabled:
          type: boolean
        endpoint:
          type: string
        slug:
          type: string
          nullable: true
        html_snippet:
          type: string
        redirect_url:
          type: string
          nullable: true
        allowed_origins:
          type: array
          items:
            type: string
        allowed_origins_inherited:
          type: boolean
        effective_allowed_origins:
          type: array
          items:
            type: string
        time_zone:
          type: string
          nullable: true
        time_zone_inherited:
          type: boolean
        effective_time_zone:
          type: string
          nullable: true
        subject_template:
          type: string
          nullable: true
        email_branding_removed:
          type: boolean
        spam_protection:
          $ref: '#/components/schemas/SpamProtectionResponse'
        field_rules:
          type: array
          items:
            $ref: '#/components/schemas/FieldRuleResponse'
        submission_count:
          type: integer
          format: int32
        monthly_usage:
          type: integer
          format: int32
        monthly_quota:
          type: integer
          format: int32
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    FormDetailResponse:
      required:
        - form
      type: object
      properties:
        ok:
          type: boolean
        form:
          $ref: '#/components/schemas/FormDetail'
    FormListResponse:
      type: object
      properties:
        ok:
          type: boolean
        forms:
          type: array
          items:
            $ref: '#/components/schemas/FormSummary'
        total:
          type: integer
          format: int32
        page:
          type: integer
          format: int32
        per_page:
          type: integer
          format: int32
    FormSummary:
      type: object
      properties:
        id:
          type: string
          format: uuid
        workspace_id:
          type: string
          format: uuid
          nullable: true
        name:
          type: string
        enabled:
          type: boolean
        endpoint:
          type: string
        submission_count:
          type: integer
          format: int32
        monthly_usage:
          type: integer
          format: int32
        monthly_quota:
          type: integer
          format: int32
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    HeldSubmissionPreview:
      required:
        - fields
        - submitted_at
      type: object
      properties:
        fields:
          type: object
          additionalProperties:
            type: string
        submitted_at:
          type: string
          format: date-time
    JsonElement: { }
    LoginRequest:
      required:
        - email
        - password
      type: object
      properties:
        email:
          type: string
        password:
          type: string
    MagicLinkRequest:
      required:
        - email
      type: object
      properties:
        email:
          maxLength: 320
          type: string
    NotificationDestinationDetailResponse:
      required:
        - destination
      type: object
      properties:
        ok:
          type: boolean
        destination:
          $ref: '#/components/schemas/NotificationDestinationResponse'
    NotificationDestinationListResponse:
      type: object
      properties:
        ok:
          type: boolean
        destinations:
          type: array
          items:
            $ref: '#/components/schemas/NotificationDestinationResponse'
    NotificationDestinationResponse:
      type: object
      properties:
        id:
          type: string
          format: uuid
        form_id:
          type: string
          format: uuid
        type:
          type: string
        config:
          $ref: '#/components/schemas/JsonElement'
        enabled:
          type: boolean
        created_at:
          type: string
          format: date-time
    NullableOfJsonElement:
      nullable: true
    OkResponse:
      type: object
      properties:
        ok:
          type: boolean
    RefreshRequest:
      required:
        - refresh_token
      type: object
      properties:
        refresh_token:
          type: string
    RegisterRequest:
      required:
        - email
        - password
      type: object
      properties:
        email:
          maxLength: 320
          type: string
        password:
          maxLength: 200
          minLength: 8
          type: string
        name:
          maxLength: 200
          type: string
          nullable: true
        time_zone:
          maxLength: 64
          type: string
          nullable: true
    RevokeApiKeyResponse:
      type: object
      properties:
        ok:
          type: boolean
        revoked:
          type: boolean
    RotateWebhookSecretResponse:
      required:
        - signing_secret
      type: object
      properties:
        ok:
          type: boolean
        signing_secret:
          type: string
    SetCaptchaRequest:
      required:
        - provider
        - site_key
        - secret_key
      type: object
      properties:
        provider:
          maxLength: 50
          type: string
        site_key:
          maxLength: 200
          type: string
        secret_key:
          maxLength: 500
          type: string
    SpamProtectionRequest:
      type: object
      properties:
        honeypot:
          type: boolean
          nullable: true
      nullable: true
    SpamProtectionResponse:
      type: object
      properties:
        honeypot:
          type: boolean
        captcha:
          $ref: '#/components/schemas/CaptchaResponse'
    SubmissionDetailResponse:
      required:
        - submission
      type: object
      properties:
        ok:
          type: boolean
        submission:
          $ref: '#/components/schemas/SubmissionResponse'
    SubmissionListResponse:
      type: object
      properties:
        ok:
          type: boolean
        submissions:
          type: array
          items:
            $ref: '#/components/schemas/SubmissionResponse'
        total:
          type: integer
          format: int32
        page:
          type: integer
          format: int32
        per_page:
          type: integer
          format: int32
    SubmissionResponse:
      type: object
      properties:
        id:
          type: string
          format: uuid
        form_id:
          type: string
          format: uuid
        fields:
          type: object
          additionalProperties:
            type: string
        files:
          type: array
          items:
            type: string
        ip:
          type: string
          nullable: true
        spam:
          type: boolean
        spam_score:
          type: integer
          format: int32
        read:
          type: boolean
        starred:
          type: boolean
        archived:
          type: boolean
        created_at:
          type: string
          format: date-time
    SubmissionStatsResponse:
      type: object
      properties:
        ok:
          type: boolean
        daily:
          type: array
          items:
            $ref: '#/components/schemas/DailyCountResponse'
    UpdateFormRequest:
      type: object
      properties:
        name:
          maxLength: 200
          type: string
          nullable: true
        enabled:
          type: boolean
          nullable: true
        redirect_url:
          maxLength: 2048
          type: string
          nullable: true
        allowed_origins:
          type: array
          items:
            type: string
          nullable: true
        subject_template:
          maxLength: 500
          type: string
          nullable: true
        email_branding_removed:
          type: boolean
          nullable: true
        slug:
          maxLength: 100
          type: string
          nullable: true
        workspace_id:
          type: string
          format: uuid
          nullable: true
        time_zone:
          maxLength: 64
          type: string
          nullable: true
        spam_protection:
          $ref: '#/components/schemas/SpamProtectionRequest'
        field_rules:
          type: array
          items:
            $ref: '#/components/schemas/FieldRuleRequest'
          nullable: true
    UpdateNotificationDestinationRequest:
      type: object
      properties:
        enabled:
          type: boolean
          nullable: true
        config:
          $ref: '#/components/schemas/NullableOfJsonElement'
    UpdateSubmissionRequest:
      type: object
      properties:
        read:
          type: boolean
          nullable: true
        starred:
          type: boolean
          nullable: true
        archived:
          type: boolean
          nullable: true
    UpdateWorkspaceDefaultSettingsRequest:
      type: object
      properties:
        allowed_origins:
          type: array
          items:
            type: string
          nullable: true
        time_zone:
          maxLength: 64
          type: string
          nullable: true
      nullable: true
    UpdateWorkspaceRequest:
      type: object
      properties:
        name:
          maxLength: 200
          type: string
          nullable: true
        default_settings:
          $ref: '#/components/schemas/UpdateWorkspaceDefaultSettingsRequest'
    VerifiedEmailDetailResponse:
      required:
        - verified_email
      type: object
      properties:
        ok:
          type: boolean
        verified_email:
          $ref: '#/components/schemas/VerifiedEmailSummary'
    VerifiedEmailListResponse:
      type: object
      properties:
        ok:
          type: boolean
        verified_emails:
          type: array
          items:
            $ref: '#/components/schemas/VerifiedEmailSummary'
    VerifiedEmailSummary:
      type: object
      properties:
        id:
          type: string
          format: uuid
        email:
          type: string
        verified_at:
          type: string
          format: date-time
          nullable: true
        created_at:
          type: string
          format: date-time
    VerifyEmailResponse:
      type: object
      properties:
        ok:
          type: boolean
        email:
          type: string
    WorkspaceCaptchaResponse:
      type: object
      properties:
        provider:
          type: string
        site_key:
          type: string
      nullable: true
    WorkspaceDefaultSettingsResponse:
      type: object
      properties:
        allowed_origins:
          type: array
          items:
            type: string
          nullable: true
        captcha:
          $ref: '#/components/schemas/WorkspaceCaptchaResponse'
        time_zone:
          type: string
          nullable: true
    WorkspaceDetailResponse:
      required:
        - workspace
      type: object
      properties:
        ok:
          type: boolean
        workspace:
          $ref: '#/components/schemas/WorkspaceResponse'
    WorkspaceListResponse:
      type: object
      properties:
        ok:
          type: boolean
        workspaces:
          type: array
          items:
            $ref: '#/components/schemas/WorkspaceResponse'
    WorkspaceResponse:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        is_default:
          type: boolean
        form_count:
          type: integer
          format: int32
        default_settings:
          $ref: '#/components/schemas/WorkspaceDefaultSettingsResponse'
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
  securitySchemes:
    Bearer:
      type: http
      description: 'Bearer token - either a Dashboard UI session JWT or a BootForm account API key (bf_live_.../bf_test_...), depending on the endpoint.'
      scheme: bearer
security:
  - Bearer: [ ]