Voice

  • Calling
  • Text messaging
  • Phone menu & routing

Marketing

  • Email campaigns
  • SMS campaigns
  • Email newsletters

Websites

  • HTML Hosting
  • Custom domains
  • Forms
Talk to salesSign in

Docs

Overview Voice SMS Team chat Team permissions
HTML forms Setup Optional fields Code examples Advanced forms Spam protection Allowed domains Deliverability
Email campaigns Sites WordPress Agents Help

HTML forms

Use an access key to post any custom form to Pathline. You keep full control of the HTML and CSS on your site.

Setup

  1. Create an access key

    Sign in to Pathline and open Forms → Access keys. Click the + next to the tab to create a key.

    Give the key a name and enter the domain where the form will live, such as example.com. You can add more domains later.

  2. Copy your key

    Copy the access key UUID, or use Copy instructions for AI on the Access keys page.

  3. Add the form to your site

    Point the form at Pathline’s submit endpoint and include your access key. Field names become labels in Messages (first_name shows as “First Name”).

  4. Test a submission

    Load the page on an allowed domain and submit. The entry should appear in Messages. If you get a 403, add the page hostname to your access key’s allowed domains (e.g. example.com).

Code examples

Build and post from HTML, JavaScript, or Next.js. Replace YOUR-ACCESS-KEY with your access key UUID.

contact.html
<style>
  .contact-form {
    display: grid;
    gap: 12px;
    padding: 24px;
    border-radius: 12px;
  }
</style>

<form class="contact-form"
      action="https://api.pathline.io/submit"
      method="POST">
  <input type="hidden" name="access_key"
         value="YOUR-ACCESS-KEY">
  <input type="text" name="name" required>
  <input type="email" name="email" required>
  <textarea name="message"></textarea>
  <button type="submit">Send</button>
</form>
const form = document.querySelector('#contact-form');

form.addEventListener('submit', async (e) => {
  e.preventDefault();

  const res = await fetch('https://api.pathline.io/submit', {
    method: 'POST',
    body: new FormData(form),
  });

  const json = await res.json();
  if (json.success) {
    window.location.href = '/thank-you';
  }
});
'use client';

export function ContactForm() {
  async function handleSubmit(e) {
    e.preventDefault();

    const res = await fetch('https://api.pathline.io/submit', {
      method: 'POST',
      body: new FormData(e.currentTarget),
    });

    const json = await res.json();
    if (json.success) {
      window.location.href = '/thank-you';
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      <input type="hidden" name="access_key"
             value="YOUR-ACCESS-KEY" />
      <input type="text" name="name" required />
      <input type="email" name="email" required />
      <textarea name="message" />
      <button type="submit">Send</button>
    </form>
  );
}
Submit URL Always use https://api.pathline.io/submit.

HTML, JavaScript, and Next.js examples run in the browser on an allowed domain. Server-side posts without a browser Origin are rejected for access-key forms.

Optional fields

Field Purpose
subject Custom email subject line for notification emails.
redirect URL to send the visitor to after a successful submit.
replyto Reply-to address for notification emails.

Advanced forms

Pathline accepts any standard HTML form field. The name on each input becomes the label in Messages. Style the form however you want. Pathline only receives the field names and values.

Field types that work

HTML Example name In Messages
<input type="text"> name Name
<input type="email"> / tel email, phone Email, Phone
<textarea> message Message
<input type="radio"> project_type Project Type
<select> service Service
<input type="checkbox"> newsletter Newsletter

Radio buttons

Use the same name on each radio in a group. Only the selected value is submitted.

<fieldset>
  <legend>What kind of project?</legend>
  <label><input type="radio" name="project_type" value="Construction" required> Construction</label>
  <label><input type="radio" name="project_type" value="Real estate"> Real Estate</label>
  <label><input type="radio" name="project_type" value="Brand / Corporate"> Brand / Corporate</label>
</fieldset>

<fieldset>
  <legend>Timeline</legend>
  <label><input type="radio" name="timeline" value="Within 30 days"> Within 30 days</label>
  <label><input type="radio" name="timeline" value="1-3 months"> 1–3 months</label>
</fieldset>

Dropdowns

A <select> works the same way: one name, one submitted value.

<label for="service">Service needed</label>
<select id="service" name="service" required>
  <option value="" disabled selected>Choose one…</option>
  <option value="Video production">Video production</option>
  <option value="Photography">Photography</option>
  <option value="Both">Both</option>
</select>

Follow-up text field

Pair a radio group with an optional text input when “Other” or a custom answer is needed. Use a different name for the text field.

<label><input type="radio" name="budget" value="Under $2,500"> Under $2,500</label>
<label><input type="radio" name="budget" value="$5K-$10K"> $5K–$10K</label>

<label for="budget_custom">Or type your budget:</label>
<input type="text" id="budget_custom" name="budget_custom" placeholder="e.g. $3,500">

Full quote-request example

A multi-step quote form with radio groups, tracking fields, contact inputs, Pathline hidden fields, and JavaScript submit.

<form id="quote-form" novalidate>
  <input type="hidden" name="access_key" value="YOUR-ACCESS-KEY-HERE">
  <input type="hidden" name="subject" value="New quote request">
  <input type="hidden" name="redirect" value="https://example.com/thank-you">
  <input type="checkbox" name="botcheck" style="display:none">

  <!-- Optional: UTM / ad tracking -->
  <input type="hidden" name="utm_source" id="utm_source">
  <input type="hidden" name="utm_medium" id="utm_medium">
  <input type="hidden" name="gclid" id="gclid">

  <!-- Client-side honeypot (hide with CSS) -->
  <div class="hp-field" aria-hidden="true">
    <input type="text" name="website_url" tabindex="-1" autocomplete="off">
  </div>
  <input type="hidden" name="form_load_time" id="form_load_time">

  <!-- Questions -->
  <p>What kind of project?</p>
  <label><input type="radio" name="project_type" value="Construction" required> Construction</label>
  <label><input type="radio" name="project_type" value="Real estate"> Real estate</label>

  <p>Timeline</p>
  <label><input type="radio" name="timeline" value="Within 30 days"> Within 30 days</label>
  <label><input type="radio" name="timeline" value="1-3 months"> 1–3 months</label>

  <label for="service">Service</label>
  <select id="service" name="service">
    <option value="Video">Video</option>
    <option value="Photo">Photo</option>
  </select>

  <!-- Contact -->
  <input type="text" name="name" placeholder="Full name" required>
  <input type="tel" name="phone" placeholder="Phone">
  <input type="email" name="email" placeholder="Email" required>
  <textarea name="message" placeholder="Project details" rows="4"></textarea>

  <button type="submit">Send</button>
</form>

<script>
  // Capture UTM params on load
  const params = new URLSearchParams(window.location.search);
  ['utm_source', 'utm_medium', 'gclid'].forEach(function (key) {
    const el = document.getElementById(key);
    if (el) el.value = params.get(key) || '';
  });
  document.getElementById('form_load_time').value = String(Date.now());

  document.getElementById('quote-form').addEventListener('submit', async function (e) {
    e.preventDefault();
    const form = e.target;

    // Client honeypot
    if (form.website_url && form.website_url.value) return;

    // Reject instant bot submits (< 3s)
    const loadTime = parseInt(form.form_load_time.value, 10);
    if (Date.now() - loadTime < 3000) return;

    const res = await fetch('https://api.pathline.io/submit', {
      method: 'POST',
      body: new FormData(form),
    });
    const json = await res.json();
    if (json.success) {
      window.location.href = form.redirect.value || 'https://example.com/thank-you';
    } else {
      alert(json.body?.message || 'Something went wrong');
    }
  });
</script>

Tips for complex forms

  • One question per name: radio groups share a name; text fields get their own.
  • Use snake_case names: project_type reads cleaner in Messages than projectType.
  • Empty fields are skipped: optional inputs left blank won’t clutter the submission.
  • Always include botcheck: add client-side honeypots and time checks on top if you want.
  • Style freely: grid layouts, custom radio labels, and multi-page wizards all work as long as fields stay inside the <form> (or you build FormData manually before fetch).

Spam protection

Built-in honeypot (botcheck)

Include a hidden checkbox named botcheck in every form. Real visitors never see it. Bots often fill every field.

If botcheck is filled in, Pathline quietly accepts the request but does not create a Message or send email.

<input type="checkbox" name="botcheck" style="display:none">

Use CSS to hide it, not type="hidden".

Extra client-side checks

You can add your own JavaScript checks before calling fetch (for example, block submits within 2 seconds of page load). Only botcheck is enforced on the server.

Allowed domains

HTML access-key forms only accept submissions from domains on your allow list. If the page hostname is not allowed, Pathline returns a 403 and the submission is rejected. Pathline checks the browser’s Origin or Referer header, not the value in your form HTML.

What to enter

  • Enter a hostname, such as example.com, not a full URL path.
  • If you paste a URL like https://www.example.com/contact, Pathline stores only www.example.com.
  • Add every site where the form is embedded. You can attach multiple domains to one access key.

How Pathline matches domains

You add Also allowed Notes
example.com www.example.com Pathline adds the www variant automatically for normal production domains.
www.example.com example.com Works both ways. You only need to add one.
staging.example.com None Subdomains are separate. Add each subdomain explicitly.
localhost:3000 None For local dev, include the port if your browser sends it in Origin.

Browser-only submissions

  • Submissions must come from a real browser on an allowed hostname.
  • curl, server-side scripts, and backend proxies are rejected because they do not send a matching browser Origin.
  • JavaScript fetch from an allowed page sends a CORS preflight; the hostname must still be on your access key.

Managing domains

Add or remove domains anytime on Forms → Access keys. In the dashboard, example.com and www.example.com are shown as a single entry.

403 errors If a live form returns 403, open the page, note the hostname in the address bar (including any subdomain or port), and add that exact hostname to the access key.

Deliverability

Pathline filters noisy and abusive submissions so your Messages inbox and notification emails stay usable. These checks apply to HTML access-key forms and Pathline-hosted forms.

Access-key forms are also restricted by your allowed domain list. Only browsers on those hostnames can post, even if someone copies your form HTML elsewhere.

Pathline Spam Agent

When the Pathline Spam Agent is enabled, submissions it flags as spam are marked as spam and appear in your Spam inbox in Messages, not in the main inbox. The visitor still receives a success response.

Non-Latin message filtering

Most form spam Pathline sees uses non-Latin scripts (Cyrillic, Greek, Arabic, CJK, Hebrew, Armenian, and similar). If any answer field contains those characters, Pathline:

  • Returns a normal success response to the visitor (same as a real submission).
  • Does not create a Message in your inbox.
  • Does not send a notification email.

Legitimate messages written in Latin characters (English, Spanish, French, German, etc.) are unaffected. If you expect real inquiries in non-Latin scripts, contact Pathline support. This filter is designed for typical English-language business sites.

Honeypot spam (botcheck)

When the hidden botcheck field is filled, Pathline also accepts the request quietly without creating a Message. See Spam protection for setup.

Documentation Terms and Conditions Privacy Policy

© 2026 Pathline