POST https://ppl-onboarding.vercel.app/api/webhooks/ghl
Content-Type: application/json
{
"ghl_contact_id": "abc123xyz", // REQUIRED — unique GHL contact ID
"first_name": "John", // REQUIRED
"last_name": "Smith", // REQUIRED
"email": "john@example.com", // REQUIRED — valid email
"phone": "+17025551234", // optional
"company_name": "Smith Funding LLC", // optional — used for onboarding URL slug
"state": "NV", // optional
"primary_vertical": "MCA", // optional — collected during onboarding if missing
"secondary_vertical": "Equipment", // optional
"batch_size": 25, // REQUIRED — positive integer, max 10,000 (can be string, auto-coerced)
"deal_amount": 1500 // REQUIRED — positive number, max 10,000,000 (can be string, auto-coerced)
}| Field | Type | Required | Notes |
|---|---|---|---|
ghl_contact_id |
string | Yes | Must be unique per broker. Used for idempotency — duplicate webhooks with same ID won't create duplicate brokers. |
first_name |
string | Yes | Auto title-cased (e.g. "john" → "John") |
last_name |
string | Yes | Auto title-cased |
email |
string | Yes | Must be valid email format. Auto lowercased. |
phone |
string | No | Any format accepted |
company_name |
string | No | Used to generate the onboarding URL slug. Falls back to broker name if missing. |
state |
string | No | US state code or full name |
primary_vertical |
string | No | Pre-populated if sent, always editable by broker during onboarding (Step 2). Options: MCA, Equipment, SBA, Real Estate, Business Line of Credit, Invoice Factoring. |
secondary_vertical |
string | No | Same options as primary. Always shown during onboarding, pre-populated if sent. |
batch_size |
number | Yes | Number of referrals in the batch. Positive integer, max 10,000. Can be sent as string — auto-coerced. |
deal_amount |
number | Yes | Total deal amount in USD. Positive number, max 10,000,000. Can be sent as string — auto-coerced. |
Note:
timezoneis not part of the webhook payload. It is auto-detected from the broker's device during onboarding (Step 2) and can be changed manually. Mapped to the nearest US timezone (Eastern, Central, Mountain, Pacific, Alaska, Hawaii).
// 201 Created
{
"onboarding_url": "https://ppl-onboarding.vercel.app/onboard/smith-funding-llc",
"broker_name": "John",
"status": "created"
}// 200 OK
{
"onboarding_url": "https://ppl-onboarding.vercel.app/onboard/smith-funding-llc",
"broker_name": "John",
"status": "exists"
}// 400 Bad Request
{
"error": "Validation failed",
"details": { ... }
}- Webhook receives the payload and validates all fields via Zod schema
- Checks if a broker with that
ghl_contact_idalready exists- If yes → returns existing onboarding URL (idempotent, safe to retry)
- If no → generates a human-readable slug token (from company name or broker name), creates the broker record, returns new onboarding URL
- The
onboarding_urlis what gets sent to the broker (via SMS/email in GHL workflow) - Broker opens the link → 7-step onboarding flow → marked as completed when they accept the policy at step 6
curl -X POST https://ppl-onboarding.vercel.app/api/webhooks/ghl \
-H "Content-Type: application/json" \
-d '{
"ghl_contact_id": "ghl_test_001",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com",
"phone": "+15551234567",
"company_name": "Doe Funding",
"primary_vertical": "MCA",
"batch_size": 20,
"deal_amount": 1300
}'The onboarding flow shows the broker their ROI breakdown:
- Price per referral =
deal_amount / batch_size - Example: $1500 deal / 25 referrals = $60 per referral
- This is calculated dynamically, never hardcoded