Opt-Ins & Submit API Reference

POST external lead submission data directly into Hermon, and query historical traffic records, UTM attributions, logs, and form submissions.

Date & Timezone Handling: All timestamps in responses are UTC, formatted as ISO 8601 (2026-01-15T10:30:00.000Z). Date-range filter parameters accept either YYYY-MM-DD (which expands to UTC day boundaries) or full ISO 8601 timestamps.
Both bounds are inclusive. Only created_at is filterable on the list endpoint (there is no updated_at on opt-ins).

Submit Endpoint

POST/api/opt-in/submit

Headers

Content-Type:application/json
x-api-key:sk_live_your_key_here

Request Body Fields

FieldTypeRequiredDescription
emailstringRequiredLead's email address
first_namestringRequiredLead's first name
sourcestringRequiredsource must be one of: CALENDLY, MANUAL, TYPEFORM, WEBINAR, NEWSLETTER, LANDING_PAGE, OTHER
last_namestringOptionalLead's last name
phone_e164stringOptionalPhone in E.164 format (e.g. +14155552671)
phone_countrystringOptionalISO country code. Required if phone_e164 provided
provider_form_idstringOptionalYour form's unique identifier
provider_form_namestringOptionalYour form's display name
external_referencestringOptionalYour unique submission ID for idempotency
questions_answersarrayOptionalQ&A pairs from your form (max 50)
trafficobjectOptionalUTM parameters and referrer data

questions_answers item

json
{
  "question": "What is your biggest challenge?",
  "answer": "Generating consistent leads",
  "position": 0
}

traffic object

json
{
  "utm_source": "facebook",
  "utm_medium": "paid",
  "utm_campaign": "q1-coaching",
  "utm_content": "video-ad-1",
  "utm_term": "coaching program",
  "referrer": "https://facebook.com",
  "landing_page": "https://yoursite.com/apply"
}
If traffic.utm_content starts with user_ (a Clerk user ID), Hermon automatically assigns that user as the setter on the lead. This enables automated setter attribution from ad tracking.

Submit Responses

201New lead created via opt-in
json
{
  "status": "success",
  "message": "Lead created via opt-in",
  "data": {
    "opt_in_id": "uuid",
    "lead_id": "uuid",
    "is_new_lead": true
  }
}
200Existing lead updated
json
{
  "status": "success",
  "message": "Opt-in recorded for existing lead",
  "data": {
    "opt_in_id": "uuid",
    "lead_id": "uuid",
    "is_new_lead": false
  }
}
401Missing or invalid API key
json
{
  "status": "error",
  "message": "Invalid or revoked API key"
}
400Validation failure
json
{
  "status": "error",
  "message": "source must be one of: CALENDLY, MANUAL, TYPEFORM, WEBINAR, NEWSLETTER, LANDING_PAGE, OTHER",
}
429Rate limit exceeded
json
{
  "status": "error",
  "message": "Too many requests"
}

Idempotency

Pass external_reference with a unique ID from your system. If the same external_reference + source combination is submitted again, Hermon returns the existing opt-in record without creating a duplicate.

json
{
  "email": "john@example.com",
  "first_name": "John",
  "source": "LANDING_PAGE",
  "external_reference": "typeform-submission-abc123"
}

List Opt-Ins Records

List Opt-Ins

Retrieve a paginated list of opt-ins. Results can be filtered by source, lead ID, and creation date.

GET/api/external/opt-ins

Query Parameters

ParameterTypeRequiredDescription
pageintegerOptionalPage number for pagination. Default: 1
limitintegerOptionalNumber of items per page. Default: 10, Max: 100
sourcestringOptionalFilter by opt-in source. See Opt-in Source Values.
lead_idstring (UUID)OptionalUUID of a specific lead. Returns opt-ins linked to that lead.
created_fromstringOptionalLower bound for created_at. Accepts YYYY-MM-DD or ISO 8601.
created_tostringOptionalUpper bound for created_at. Accepts YYYY-MM-DD or ISO 8601.

Code Examples

curl -X GET "https://api.hermon.io/api/external/opt-ins?page=1&limit=10&source=CALENDLY&lead_id=e799c30f-9da7-4fd7-9552-83b96a9bfac2" \
  -H "Content-Type: application/json" \
  -H "x-api-key: sk_live_your_key_here"

Response Example

json
{
  "success": true,
  "message": "Opt-ins fetched successfully",
  "data": [
    {
      "id": "optin_e5f6a7b8-c9d0-1234-efgh-345678901234",
      "lead_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "source": "TYPEFORM",
      "provider_form_id": "form_abc123def456",
      "provider_form_name": "Coaching Application Form",
      "external_reference": "TYPEFORM-response-abc123",
      "created_at": "2026-01-15T10:30:00.000Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 1,
    "totalPages": 1,
    "hasNext": false,
    "hasPrev": false
  }
}

Get Opt-In Details

Fetch detailed information for a single opt-in submission record by its unique UUID.

GET/api/external/opt-ins/:id

Path Parameters

:idRequired. The unique opt-in UUID.

Opt-In Object Fields

FieldTypeDescription
idstring (UUID)Unique identifier for the opt-in.
lead_idstring (UUID)ID of the lead this opt-in created or matched.
sourcestring (enum)The system or integration that captured the opt-in. See Opt-in Source Values.
provider_form_idstring | nullThe form's identifier in the originating provider (e.g. Typeform form ID). null for manual entries.
provider_form_namestring | nullThe form's display name in the originating provider. null for manual entries.
external_referencestring | nullThe provider's unique reference for this specific submission (e.g. Typeform response ID).
created_atstring (ISO 8601)UTC timestamp when the opt-in was captured.
question_answersarrayOrdered list of form question/answer pairs. See Question Answer Object [Details API Only].
traffic_attributionobjectUTM and referrer data. See Traffic Attribution Object [Details API Only].

Code Examples

curl -X GET "https://api.hermon.io/api/external/opt-ins/522b1759-d354-472c-8fb2-1a9bbc69eb9b" \
  -H "Content-Type: application/json" \
  -H "x-api-key: sk_live_your_key_here"

Response Example

json
{
  "success": true,
  "message": "Opt-in fetched successfully",
  "data": {
    "id": "optin_e5f6a7b8-c9d0-1234-efgh-345678901234",
    "lead_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "source": "TYPEFORM",
    "provider_form_id": "form_abc123def456",
    "provider_form_name": "Coaching Application Form",
    "external_reference": "TYPEFORM-response-abc123",
    "created_at": "2026-01-15T10:30:00.000Z",
    "question_answers": [
      {
        "id": "qa_001",
        "question": "What is your biggest business challenge right now?",
        "answer": "Struggling to convert leads into high-ticket clients consistently",
        "position": 1
      },
      {
        "id": "qa_002",
        "question": "What is your monthly revenue?",
        "answer": "$10,000 - $25,000",
        "position": 2
      },
      {
        "id": "qa_003",
        "question": "How did you hear about us?",
        "answer": "Facebook Ad",
        "position": 3
      }
    ],
    "traffic_attribution": {
      "utm_source": "facebook",
      "utm_medium": "paid_social",
      "utm_campaign": "q1-2026-coaching",
      "utm_content": "video-ad-v2",
      "utm_term": null,
      "referrer": "https://www.facebook.com/",
      "landing_page": "https://example.com/apply"
    }
  }
}

Values Reference

Opt-in Source Values

ValueDescription
CALENDLYCalendly form/event
ICLOSEDiClosed integration
GOHIGHLEVELGoHighLevel form
MANUALManually created
TYPEFORMTypeform submission
WEBINARWebinar registration
NEWSLETTERNewsletter signup
LANDING_PAGELanding page form
OTHEROther source

Nested Objects Reference

Question Answer Object Fields

FieldTypeDescription
idstringUnique identifier for this question/answer pair.
questionstringThe form question text.
answerstring | nullThe respondent's answer. null if the question was skipped.
positionintegerDisplay order (1-indexed).

Traffic Attribution Object Fields

FieldTypeDescription
utm_sourcestring | nullUTM source (e.g. "facebook", "google").
utm_mediumstring | nullUTM medium (e.g. "paid_social", "email").
utm_campaignstring | nullUTM campaign name.
utm_contentstring | nullUTM content variant.
utm_termstring | nullUTM keyword term.
referrerstring | nullHTTP referrer URL (the page that linked to the form).
landing_pagestring | nullURL of the landing page the visitor was on when they submitted the form.

Management Errors

401Missing or invalid API key
json
{
  "status": "error",
  "message": "Invalid or revoked API key"
}
404Resource not found
json
{
  "status": "error",
  "message": "Resource not found"
}
429Rate limit exceeded
json
{
  "status": "error",
  "message": "Too many requests"
}