HeyForm API

RESTful API for programmatically managing forms, submissions, webhooks, and workspace resources. Supports creating and publishing forms, retrieving response data, configuring integrations, and embedding forms via a JavaScript embed library.

OpenAPI Specification

heyform-heyform-api-openapi.yml Raw ↑
openapi: 3.0.3
info:
  title: HeyForm API
  description: >-
    HeyForm is an open-source conversational form builder providing REST and
    GraphQL endpoints for managing forms, submissions, workspaces, integrations,
    and webhooks. The primary data API uses GraphQL; this document covers the
    publicly accessible REST endpoints discovered in the open-source codebase.
  version: 1.0.0
  contact:
    name: HeyForm Support
    url: https://docs.heyform.net
  license:
    name: AGPL-3.0
    url: https://github.com/heyform/heyform/blob/main/LICENSE
externalDocs:
  description: HeyForm Documentation
  url: https://docs.heyform.net
servers:
  - url: https://api.heyform.net
    description: HeyForm Cloud API
  - url: http://localhost:8000
    description: Self-hosted HeyForm instance (default port)

tags:
  - name: Config
    description: Runtime configuration
  - name: Auth
    description: Authentication and social login (OAuth)
  - name: Forms
    description: Form rendering (public endpoint)
  - name: Submissions
    description: Export form submission data
  - name: Upload
    description: File upload
  - name: Images
    description: Image proxy and resizing
  - name: GraphQL
    description: Primary data API (GraphQL over HTTP)

paths:
  /api/config:
    get:
      operationId: getConfig
      summary: Get runtime configuration
      description: >-
        Returns the public runtime configuration for the HeyForm application,
        including homepage URL, feature flags, and third-party integration keys.
      tags:
        - Config
      responses:
        '200':
          description: Runtime configuration object
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RuntimeConfig'
              example:
                homepageURL: 'https://heyform.net'
                websiteURL: 'https://heyform.net'
                appDisableRegistration: false
                cookieDomain: 'heyform.net'
                enableGoogleFonts: true
                stripePublishableKey: 'pk_live_...'
                googleRecaptchaKey: '6Le...'
                verifyEmailResendCooldownSeconds: 60

  /api/export/submissions:
    get:
      operationId: exportSubmissions
      summary: Export form submissions as CSV
      description: >-
        Downloads all submissions for a given form as a CSV file. Requires
        authentication and the caller must own or have access to the specified form.
      tags:
        - Submissions
      security:
        - cookieAuth: []
      parameters:
        - name: formId
          in: query
          required: true
          description: The unique identifier of the form whose submissions to export.
          schema:
            type: string
          example: abc123xyz
      responses:
        '200':
          description: CSV file containing all form submissions
          content:
            text/csv:
              schema:
                type: string
                format: binary
          headers:
            Content-Disposition:
              schema:
                type: string
              example: 'attachment; filename="My%20Form-2026-06-13.csv"'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/upload:
    post:
      operationId: uploadFile
      summary: Upload a file
      description: >-
        Uploads a file (image or document) to the HeyForm storage backend.
        Returns the URL at which the uploaded file can be accessed. SVG files
        are blocked for security reasons.
      tags:
        - Upload
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - file
              properties:
                file:
                  type: string
                  format: binary
                  description: The file to upload.
      responses:
        '201':
          description: File uploaded successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UploadResult'
              example:
                filename: 'photo.jpg'
                url: 'https://heyform.net/static/upload/photo-abc123.jpg'
                size: 204800
        '400':
          $ref: '#/components/responses/BadRequest'

  /api/image:
    get:
      operationId: proxyImage
      summary: Proxy and resize an image
      description: >-
        Fetches a remote image from an allowed host, optionally resizes it, and
        returns the result with long-lived cache headers. Useful for embedding
        external images in forms without leaking user IP addresses.
      tags:
        - Images
      parameters:
        - name: url
          in: query
          required: true
          description: The URL of the remote image to proxy.
          schema:
            type: string
            format: uri
          example: 'https://images.unsplash.com/photo-abc123'
        - name: w
          in: query
          required: false
          description: Target width in pixels.
          schema:
            type: integer
            minimum: 1
          example: 800
        - name: h
          in: query
          required: false
          description: Target height in pixels.
          schema:
            type: integer
            minimum: 1
          example: 600
      responses:
        '200':
          description: Image content
          content:
            image/*:
              schema:
                type: string
                format: binary
          headers:
            Cache-Control:
              schema:
                type: string
              example: 'public, max-age=315360000, must-revalidate'
        '204':
          description: Empty response when the image cannot be fetched or is invalid.
        '400':
          $ref: '#/components/responses/BadRequest'

  /form/{formId}:
    get:
      operationId: renderForm
      summary: Render a public form
      description: >-
        Serves the HTML shell for a published form. This is the embeddable
        public-facing form page. The form data itself is loaded dynamically via
        the GraphQL endpoint.
      tags:
        - Forms
      parameters:
        - name: formId
          in: path
          required: true
          description: The unique identifier of the form to render.
          schema:
            type: string
          example: abc123xyz
      responses:
        '200':
          description: HTML page containing the rendered form
          content:
            text/html:
              schema:
                type: string

  /connect/{kind}:
    get:
      operationId: socialLoginInitiate
      summary: Initiate social login (OAuth)
      description: >-
        Redirects the user to the OAuth provider's authorization URL.
        Supported providers include Google, GitHub, and Apple.
      tags:
        - Auth
      parameters:
        - name: kind
          in: path
          required: true
          description: The OAuth provider identifier (e.g. google, github, apple).
          schema:
            type: string
            enum:
              - google
              - github
              - apple
          example: google
        - name: state
          in: query
          required: true
          description: >-
            Browser ID / CSRF state token generated by the client to correlate
            the callback.
          schema:
            type: string
          example: DMbcJqLJ
        - name: redirect_uri
          in: query
          required: false
          description: Optional URI to redirect to after successful login.
          schema:
            type: string
            format: uri
      responses:
        '302':
          description: Redirect to OAuth provider authorization URL
          headers:
            Location:
              schema:
                type: string
                format: uri
        '200':
          description: >-
            Error page rendered in HTML when the state is missing or the
            provider is unsupported.
          content:
            text/html:
              schema:
                type: string

  /connect/{kind}/callback:
    get:
      operationId: socialLoginCallbackGet
      summary: Handle OAuth callback (GET)
      description: >-
        Receives the OAuth authorization code from the provider (GET variant,
        used by most providers). Validates state, exchanges code for tokens,
        and logs the user in.
      tags:
        - Auth
      parameters:
        - name: kind
          in: path
          required: true
          description: The OAuth provider identifier.
          schema:
            type: string
            enum:
              - google
              - github
              - apple
          example: google
        - name: code
          in: query
          required: false
          description: Authorization code returned by the OAuth provider.
          schema:
            type: string
        - name: state
          in: query
          required: true
          description: CSRF state token to verify.
          schema:
            type: string
      responses:
        '302':
          description: Redirect to dashboard after successful login
          headers:
            Location:
              schema:
                type: string
        '200':
          description: Error page on failure
          content:
            text/html:
              schema:
                type: string
    post:
      operationId: socialLoginCallbackPost
      summary: Handle OAuth callback (POST)
      description: >-
        Receives the OAuth authorization code from the provider via POST (used
        by Sign in with Apple which posts directly to the backend).
      tags:
        - Auth
      parameters:
        - name: kind
          in: path
          required: true
          description: The OAuth provider identifier.
          schema:
            type: string
            enum:
              - apple
          example: apple
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                code:
                  type: string
                  description: Authorization code from Apple.
                state:
                  type: string
                  description: CSRF state token.
      responses:
        '302':
          description: Redirect to dashboard after successful login
        '200':
          description: Error page on failure
          content:
            text/html:
              schema:
                type: string

  /graphql:
    post:
      operationId: graphqlEndpoint
      summary: GraphQL API endpoint
      description: >-
        The primary HeyForm data API. All form management operations (create,
        update, delete, publish), user operations (login, sign-up, password
        reset), submission retrieval, project management, team management,
        integration configuration, and the public form open/submit flow are
        handled through this GraphQL endpoint. Authentication uses HTTP-only
        cookies set during login. Key mutations and queries include:
        login, signUp, createForm, updateFormSchemas, publishForm, deleteForm,
        openForm, completeSubmission, submissions, deleteSubmission,
        createProject, createTeam, updateIntegrationSettings.
      tags:
        - GraphQL
      security:
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GraphQLRequest'
            examples:
              openForm:
                summary: Open a published form (public)
                value:
                  query: |
                    query openForm($input: OpenFormInput!) {
                      openForm(input: $input)
                    }
                  variables:
                    input:
                      formId: abc123xyz
              completeSubmission:
                summary: Submit answers to a form (public)
                value:
                  query: |
                    mutation completeSubmission($input: CompleteSubmissionInput!) {
                      completeSubmission(input: $input) {
                        clientSecret
                      }
                    }
                  variables:
                    input:
                      formId: abc123xyz
                      openToken: eyJ...
                      answers:
                        - id: field1
                          value: Jane Doe
              login:
                summary: Authenticate with email and password
                value:
                  query: |
                    query login($input: LoginInput!) {
                      login(input: $input)
                    }
                  variables:
                    input:
                      email: [email protected]
                      password: secret
              createForm:
                summary: Create a new form
                value:
                  query: |
                    mutation createForm($input: CreateFormInput!) {
                      createForm(input: $input)
                    }
                  variables:
                    input:
                      projectId: proj123
                      name: Customer Feedback
      responses:
        '200':
          description: GraphQL response (errors are returned inline per the GraphQL spec)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GraphQLResponse'

components:
  securitySchemes:
    cookieAuth:
      type: apiKey
      in: cookie
      name: heyform_sid
      description: >-
        Session cookie set by the login mutation or OAuth callback. All
        authenticated GraphQL mutations and the CSV export endpoint require
        this cookie.

  schemas:
    RuntimeConfig:
      type: object
      description: Public runtime configuration returned by /api/config.
      properties:
        homepageURL:
          type: string
          format: uri
          description: Application homepage URL.
        websiteURL:
          type: string
          format: uri
          description: Website URL (may match homepageURL).
        appDisableRegistration:
          type: boolean
          description: Whether new user registration is disabled on this instance.
        cookieDomain:
          type: string
          description: Domain scope for authentication cookies.
        enableGoogleFonts:
          type: boolean
          description: Whether Google Fonts are loaded in the form renderer.
        stripePublishableKey:
          type: string
          description: Stripe publishable API key for payment forms.
        googleRecaptchaKey:
          type: string
          description: Google reCAPTCHA site key for spam protection.
        verifyEmailResendCooldownSeconds:
          type: integer
          description: Seconds the user must wait before requesting another verification email.

    UploadResult:
      type: object
      description: Result of a successful file upload.
      required:
        - filename
        - url
        - size
      properties:
        filename:
          type: string
          description: Original filename of the uploaded file.
        url:
          type: string
          format: uri
          description: Publicly accessible URL of the uploaded file.
        size:
          type: integer
          description: File size in bytes.

    Answer:
      type: object
      description: A single answer submitted for a form field.
      required:
        - id
      properties:
        id:
          type: string
          description: The field identifier this answer is for.
        value:
          description: >-
            The answer value. Type depends on the field kind (string for
            short_text, array for multiple_choice, object for payment, etc.).
          oneOf:
            - type: string
            - type: number
            - type: boolean
            - type: array
              items: {}
            - type: object

    WebhookPayload:
      type: object
      description: >-
        JSON payload delivered by HeyForm to a configured webhook URL when a
        new form submission is received.
      properties:
        id:
          type: string
          description: Unique submission identifier.
          example: sub_abc123
        formId:
          type: string
          description: Identifier of the form that received the submission.
          example: form_xyz789
        formName:
          type: string
          description: Display name of the form.
          example: Customer Feedback
        fields:
          type: array
          description: Full field configuration array (metadata about each question).
          items:
            $ref: '#/components/schemas/FormField'
        answers:
          type: array
          description: Array of answers provided by the respondent.
          items:
            $ref: '#/components/schemas/SubmissionAnswer'
        hiddenFields:
          type: array
          description: Pre-populated or system hidden fields included in the submission.
          items:
            type: object
            properties:
              id:
                type: string
              value:
                type: string
        variables:
          type: array
          description: Calculated variables (e.g. quiz scores) derived from the submission.
          items:
            type: object
            properties:
              id:
                type: string
              name:
                type: string
              value:
                type: number

    FormField:
      type: object
      description: Metadata describing a single field (question) within a form.
      properties:
        id:
          type: string
          description: Unique field identifier.
        title:
          type: string
          description: The question text displayed to the respondent.
        kind:
          type: string
          description: Field type.
          enum:
            - short_text
            - long_text
            - multiple_choice
            - picture_choice
            - yes_no
            - rating
            - opinion_scale
            - date
            - time
            - number
            - email
            - url
            - phone_number
            - file_upload
            - payment
            - signature
            - thank_you
            - statement
            - welcome
            - group

    SubmissionAnswer:
      type: object
      description: A single answer within a webhook submission payload.
      properties:
        id:
          type: string
          description: Field identifier.
        title:
          type: string
          description: The question text.
        kind:
          type: string
          description: Field type (matches FormField.kind enum).
        value:
          description: The respondent's answer value.

    GraphQLRequest:
      type: object
      required:
        - query
      properties:
        query:
          type: string
          description: GraphQL query or mutation document.
        variables:
          type: object
          description: Variable values for the query.
          additionalProperties: true
        operationName:
          type: string
          description: Name of the operation to execute (when the document contains multiple).

    GraphQLResponse:
      type: object
      properties:
        data:
          type: object
          description: The data returned by the GraphQL operation.
          additionalProperties: true
        errors:
          type: array
          description: Array of GraphQL errors, if any.
          items:
            type: object
            properties:
              message:
                type: string
              locations:
                type: array
                items:
                  type: object
                  properties:
                    line:
                      type: integer
                    column:
                      type: integer
              path:
                type: array
                items: {}
              extensions:
                type: object
                additionalProperties: true

    Error:
      type: object
      properties:
        statusCode:
          type: integer
        message:
          type: string
        error:
          type: string

  responses:
    BadRequest:
      description: Bad request — invalid input or business logic violation
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            statusCode: 400
            message: The form does not exist
            error: Bad Request
    Unauthorized:
      description: Authentication required
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            statusCode: 401
            message: Unauthorized
            error: Unauthorized