My App

POST /api/v1/message-event

GHL webhook handler for inbound and outbound messages

Message Event

Processes GHL message webhooks — handles deduplication, contact lookup, conversation management, sleep mode, channel exclusion, and AI response triggering.

Volume: ~41M runs/week | Auth: Location token (via SubAccount lookup)

Request

POST /api/v1/message-event
Content-Type: application/json

Body Parameters

FieldTypeRequiredDescription
locationIdstringGHL location ID
messageTypestringChannel type (SMS, Email, etc.)
messageIdstringGHL message ID (used for dedup)
contactIdstringGHL contact ID
conversationIdstringGHL conversation ID
bodystringMessage body text
directionstringinbound or outbound
typestringMessage type (Custom normalizes to SMS)
sourcestringMessage source
dateAddedstringISO timestamp
statusstringMessage status
attachmentsarrayFile attachments
appIdstringGHL app ID
threadIdstringThread ID
webhookIdstringWebhook ID

Response

All responses return HTTP 200 (webhook best practice).

Missing messageType

{ "messageType": false }

Location not found

{ "status": "location doesnt exist" }

Archived account

{ "status": "Archived account" }

Duplicate message

{ "messageId": false }

AI response triggered

{ "status": "ai response pending" }

Sleep mode active

{ "direction": "inbound", "sleep": true }

Channel excluded

{ "status": "channel excluded" }

AI off (contact tag)

{ "status": "ai_off" }

Success

{ "status": "sent to platform" }

Test with cURL

curl -X POST http://localhost:3000/api/v1/message-event \
  -H "Content-Type: application/json" \
  -d '{
    "locationId": "your_location_id",
    "messageType": "SMS",
    "messageId": "msg_test_001",
    "contactId": "contact_123",
    "conversationId": "conv_456",
    "body": "Hello, I need help",
    "direction": "inbound"
  }'

Pipeline Flow

  1. Validate messageType exists
  2. Look up SubAccount by locationId (Prisma)
  3. Check archive status and access token
  4. Dedup check by ghlMessageId (Prisma)
  5. Create message record (Prisma)
  6. Fetch contact from GHL API
  7. Parallel: active tags, conversation upsert, ingestion
  8. Link message to conversation
  9. Assistant lookup → sleep check → AI run decision
  10. If AI enabled: add tag → mark replying → trigger chatRun

On this page