Skip to main content
All Docs
FeaturesPurple PepperUpdated April 7, 2026

In-App Support Contact Form

In-App Support Contact Form

As of v0.1.59, users can submit support requests directly from any page in the dashboard or the public contact page without leaving the application. All submissions are stored in the database, optionally forwarded to an external system, and optionally trigger an internal notification email.

How It Works

There are two entry points to the support form:

  1. Dashboard floating button — A "Get in Touch" button is fixed to the bottom-right corner of every authenticated page. Clicking it opens the support modal.
  2. Contact page — A "Need quick help? Open support form" button appears in the hero section of the public contact/help centre page.

Both entry points open the same SupportContactModal.

The Support Form

The modal contains the following fields:

FieldRequiredConstraints
NameYesMax 200 characters
EmailYesValid email, max 320 characters
SubjectYesMax 300 characters
MessageYesMax 10,000 characters
AttachmentsNoUp to 5 files, 10 MB each

Supported attachment types: images, PDF, CSV, XLSX, DOCX, TXT

When a user is authenticated, the name and email fields are pre-filled from their session. The modal can be dismissed using the × button or by clicking the backdrop; the rest of the page is unaffected.

After a successful submission, the modal displays a confirmation message.

API Endpoint

POST /api/support

This is a public endpoint — no authentication is required. It accepts submissions from both authenticated dashboard users and anonymous public visitors.

Request Body

{
  "name": "Jane Smith",
  "email": "jane@example.com",
  "subject": "Cannot access billing settings",
  "message": "When I navigate to billing I get a 403 error...",
  "attachmentUrls": ["https://cdn.example.com/screenshot.png"],
  "sourcePage": "/dashboard/billing",
  "orgId": "org_abc123",
  "userId": "user_xyz456"
}
FieldTypeRequiredDescription
namestringYesSubmitter's full name
emailstringYesSubmitter's email address
subjectstringYesShort description of the issue
messagestringYesFull support message
attachmentUrlsstring[]NoArray of pre-uploaded file URLs (max 5)
sourcePagestringNoPage path the form was submitted from
orgIdstringNoOrganisation ID (from session)
userIdstringNoUser ID (from session)

Responses

Success — 201 Created

{ "success": true, "id": "<ticket-id>" }

Validation error — 400 Bad Request

{
  "error": "Validation failed",
  "details": {
    "email": ["Please enter a valid email address"]
  }
}

Server error — 500 Internal Server Error

{ "error": "An unexpected error occurred. Please try again later." }

Database

Every submission is stored in the support_tickets table. The record includes:

  • Submitter name, email, subject, message
  • Attachment URLs
  • Source page, IP address
  • User ID and org ID (when authenticated)
  • Ticket status (default: open)
  • Webhook delivery status and any error message
  • Whether an internal notification email was sent
  • createdAt / updatedAt timestamps

External Webhook Integration

If SUPPORT_WEBHOOK_URL is configured, every new ticket is forwarded to that URL as a POST request with a JSON body:

{
  "id": "<ticket-id>",
  "name": "Jane Smith",
  "email": "jane@example.com",
  "subject": "Cannot access billing settings",
  "message": "When I navigate to billing I get a 403 error...",
  "attachmentUrls": [],
  "sourcePage": "/dashboard/billing",
  "orgId": "org_abc123",
  "submittedAt": "2026-04-07T12:00:00.000Z"
}

If SUPPORT_WEBHOOK_SECRET is also set, it is sent as an X-Webhook-Secret header so the receiving service can authenticate the request.

The webhook call has a 10-second timeout. Failures are logged and captured as errors but do not affect the response to the user — the ticket is always saved to the database regardless.

Email Notifications

When the Resend email integration is configured and a notification email address is set, a formatted HTML email is sent to that address for each new ticket. The email includes all submitted fields and the ticket ID.

The notification address is resolved in this order:

  1. SUPPORT_NOTIFY_EMAIL
  2. CONTACT_FORM_NOTIFY_EMAIL (fallback)

Environment Variables

All three variables are optional. The support form works without any of them — tickets are always stored in the database.

VariableDescription
SUPPORT_WEBHOOK_URLExternal webhook endpoint to forward tickets to (e.g. Zendesk API, Zapier, email relay)
SUPPORT_WEBHOOK_SECRETSecret token sent as X-Webhook-Secret for webhook authentication
SUPPORT_NOTIFY_EMAILInternal email address to receive ticket notifications; falls back to CONTACT_FORM_NOTIFY_EMAIL

Using SupportContactButton Outside the Dashboard

The SupportContactButton component accepts optional props to pre-fill user context in unauthenticated or portal contexts:

import { SupportContactButton } from "@/components/support-contact-button";

<SupportContactButton
  userName="Jane Smith"
  userEmail="jane@example.com"
  orgId="org_abc123"
/>

When no props are passed and the user is authenticated, the component reads name and email from the NextAuth session automatically.

Using SupportContactModal Directly

You can render the modal directly without the floating button:

import { SupportContactModal } from "@/components/support-contact-modal";

{showModal && (
  <SupportContactModal
    onClose={() => setShowModal(false)}
    defaultName="Jane Smith"
    defaultEmail="jane@example.com"
  />
)}