Skip to main content
PushMail.dev

Forms

Create embeddable signup forms that capture contacts, apply tags, add to lists, and enroll in sequences automatically.

Overview

Forms let you collect email subscribers directly from your website without writing backend code. Each form has a unique slug and can be shared as a hosted page (/f/{slug}) or embedded via iframe. When a visitor submits a form, PushMail automatically creates or updates the contact and runs any configured auto-actions (tagging, list assignment, sequence enrollment).

The form object

{
  "id": 1,
  "orgId": 1,
  "siteId": 1,
  "name": "Newsletter Signup",
  "slug": "a1b2c3d4e5f6",
  "designJson": "{...}",
  "status": "active",
  "sequenceId": 3,
  "listId": 1,
  "tags": "[\"newsletter\"]",
  "notifyEmail": "leads@yourdomain.com",
  "notifySubject": null,
  "doubleOptIn": false,
  "submissionCount": 142,
  "createdAt": "2026-03-01T10:00:00.000Z",
  "updatedAt": "2026-03-01T10:00:00.000Z"
}

Status values

StatusDescription
draftForm is being designed, not publicly accessible
activeForm is live and accepting submissions
archivedForm is disabled and no longer accepting submissions

List forms

GET /v1/forms

Returns all forms for the authenticated organization. Optionally filter by site.

ParameterTypeDescription
siteIdintegerFilter forms by site ID (query parameter)
Request
curl https://pushmail.dev/api/v1/forms?siteId=1 \
  -H "Authorization: Bearer pm_live_YOUR_KEY"
Response
{
  "data": {
    "forms": [
      { "id": 1, "name": "Newsletter Signup", "slug": "a1b2c3d4e5f6", "status": "active", "submissionCount": 142, "..." : "..." }
    ]
  }
}

Create a form

POST /v1/forms

ParameterTypeDescription
siteIdrequiredintegerThe site this form belongs to
namerequiredstringDisplay name for the form (max 200 chars)
designJsonstringJSON string of form design (fields, styles, settings)
sequenceIdinteger | nullSequence to auto-enroll contacts in on submission
listIdinteger | nullList to add contacts to on submission
tagsstring[]Tag names to apply to contacts on submission
notifyEmailstring | nullEmail this address on each submission (Reply-To is the submitter). Null disables.
notifySubjectstring | nullSubject for the notification email (default: "New {form name} submission")
doubleOptInbooleanRequire email confirmation before subscribing (default: false)
Request
curl -X POST https://pushmail.dev/api/v1/forms \
  -H "Authorization: Bearer pm_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "siteId": 1,
    "name": "Newsletter Signup",
    "listId": 1,
    "tags": ["newsletter"]
  }'
Response (201)
{
  "data": {
    "form": {
      "id": 1,
      "slug": "a1b2c3d4e5f6",
      "name": "Newsletter Signup",
      "status": "draft",
      "..."  : "..."
    }
  }
}

A random 16-character hex slug is generated automatically. Use this slug to build the public form URL: https://pushmail.dev/f/{slug}.

Get a form

GET /v1/forms/:id

Request
curl https://pushmail.dev/api/v1/forms/1 \
  -H "Authorization: Bearer pm_live_YOUR_KEY"

Update a form

PUT /v1/forms/:id

ParameterTypeDescription
namestringUpdate display name
designJsonstringUpdate form design JSON
statusstringSet status: draft, active, or archived
sequenceIdinteger | nullUpdate sequence auto-enrollment
listIdinteger | nullUpdate list auto-assignment
tagsstring[]Update auto-applied tags
notifyEmailstring | nullUpdate the submission-notification address (null disables)
notifySubjectstring | nullUpdate the notification email subject
doubleOptInbooleanToggle double opt-in
Request
curl -X PUT https://pushmail.dev/api/v1/forms/1 \
  -H "Authorization: Bearer pm_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "status": "active" }'

Delete a form

DELETE /v1/forms/:id

Deleting a form also deletes all its submissions (cascade).

Request
curl -X DELETE https://pushmail.dev/api/v1/forms/1 \
  -H "Authorization: Bearer pm_live_YOUR_KEY"

List submissions

GET /v1/forms/:id/submissions

Returns paginated submissions for a form.

ParameterTypeDescription
pageintegerPage number (default: 1)
limitintegerItems per page (default: 50, max: 100)
Request
curl https://pushmail.dev/api/v1/forms/1/submissions?page=1&limit=20 \
  -H "Authorization: Bearer pm_live_YOUR_KEY"
Response
{
  "data": {
    "submissions": [
      {
        "id": 1,
        "formId": 1,
        "contactId": 42,
        "siteId": 1,
        "data": "{\"email\":\"jane@example.com\",\"firstName\":\"Jane\"}",
        "ipAddress": "203.0.113.1",
        "userAgent": "Mozilla/5.0 ...",
        "createdAt": "2026-03-05T14:30:00.000Z"
      }
    ],
    "pagination": { "page": 1, "limit": 20, "total": 1, "totalPages": 1 }
  }
}

Public submission endpoint

POST /v1/forms/:id/submit

This endpoint is public (no authentication required) and processes form submissions from your website visitors.

The endpoint:

  • Looks up the form by ID and verifies it is active
  • Parses submitted field values and maps them to contact fields using the form's designJson
  • Creates or updates the contact (upsert by email within the site)
  • Applies configured tags, list membership, and sequence enrollment
  • Sends a notification email if notifyEmail is set (see Submission notifications)
  • Records the submission and increments the form's submission counter
  • Rate limited to 10 submissions per IP per minute
  • Returns CORS headers for cross-origin embedding
Request
curl -X POST https://pushmail.dev/api/v1/forms/1/submit \
  -H "Content-Type: application/json" \
  -d '{ "email": "jane@example.com", "firstName": "Jane" }'
Response
{
  "data": {
    "success": true,
    "message": "Thanks for submitting!"
  }
}

Submission notifications

Set notifyEmail on a form to have PushMail email that address every time the form is submitted. This is how you route form submissions into a shared inbox or helpdesk.

The notification is a plain operational email — no unsubscribe footer, no open/click tracking. Critically, its Reply-To is the person who submitted the form, so replying to the notification from your inbox reaches the submitter directly. The From display name is {submitter} via {form name}, and the body lists every submitted field.

Enable notifications
curl -X PUT https://pushmail.dev/api/v1/forms/1 \
  -H "Authorization: Bearer pm_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "notifyEmail": "leads@yourdomain.com" }'

Set notifySubject to override the default subject (New {form name} submission). Sending the notification consumes one email credit and uses the organization's sending config, so its From domain must be a verified sending domain. A notification failure never blocks the submission itself.

Notifications can also be configured per form in the dashboard form editor via the Notifications button in the toolbar.

Hosted form page

Each form with an active status is accessible at:

https://pushmail.dev/f/{slug}

This serves a standalone HTML page with the rendered form. The page is fully styled based on the form's designJson settings and submits to the public submission endpoint via JavaScript.

You can also embed the hosted page in your site with an iframe:

<iframe src="https://pushmail.dev/f/a1b2c3d4e5f6"
  style="width:100%;border:none;min-height:500px;"
  loading="lazy"></iframe>

On this page