# Messages

## Handle Custom Channel Message

> Handles incoming messages from custom channels. Campaign Assignment Priority - 1. Explicit campaignId (highest priority) 2. Keyword matching (existing logic) 3. Default campaign (fallback). Backwards Compatibility - All new fields are optional. Existing integrations continue to work unchanged.

```json
{"openapi":"3.1.0","info":{"title":"DM Champ API","version":"1.0.0"},"servers":[{"url":"https://api.dmchamp.com/v1","description":"Production API Server"}],"security":[{"ApiKeyAuth":[]},{"UserIdAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"query","name":"apiKey","description":"Your DM Champ API key. Obtain from Settings → API Keys."},"UserIdAuth":{"type":"apiKey","in":"query","name":"userId","description":"Your DM Champ User ID. Alternative to apiKey authentication. Cannot be used for agency-only endpoints."}},"parameters":{"ApiKeyParam":{"name":"apiKey","in":"query","description":"API key for authentication. At least one of apiKey or userId is required for protected endpoints.","required":false,"schema":{"type":"string"}}}},"paths":{"/incoming-custom-channel-message":{"post":{"summary":"Handle Custom Channel Message","description":"Handles incoming messages from custom channels. Campaign Assignment Priority - 1. Explicit campaignId (highest priority) 2. Keyword matching (existing logic) 3. Default campaign (fallback). Backwards Compatibility - All new fields are optional. Existing integrations continue to work unchanged.","tags":["Messages"],"parameters":[{"$ref":"#/components/parameters/ApiKeyParam"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customData","messageType"],"properties":{"customData":{"type":"object","required":["body"],"properties":{"messageSid":{"type":"string","description":"Unique identifier for the message"},"id":{"type":"string","description":"Alternative unique identifier for the message"},"fromId":{"type":"string","description":"ID of the sender"},"toId":{"type":"string","description":"ID of the receiver"},"body":{"type":"string","description":"Message content"},"status":{"type":"string","description":"Message status","default":"received"},"mediaUrl":{"type":["string","null"],"description":"URL to media content (if any)"},"mediaContentType":{"type":["string","null"],"description":"MIME type of media content"},"channel":{"type":["string","null"],"description":"Custom channel identifier"},"campaignId":{"type":["string","null"],"description":"Explicit campaign ID to assign contact to (highest priority)"},"firstName":{"type":["string","null"],"description":"Contact's first name (for contact creation/update)"},"lastName":{"type":["string","null"],"description":"Contact's last name (for contact creation/update)"},"email":{"type":["string","null"],"description":"Contact's email address (for contact creation/update)"}}},"messageType":{"type":"string","description":"Type of message (e.g., text, reaction)","default":"text"}}}}}},"responses":{"200":{"description":"Message processed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"messageId":{"type":"string"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"string","description":"Additional error details"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}}}}
```

## Handle Custom Channel Message (Alternative)

> Alternative endpoint for handling incoming messages from custom channels. Same functionality as /incoming-custom-channel-message. Campaign Assignment Priority - 1. Explicit campaignId (highest priority) 2. Keyword matching (existing logic) 3. Default campaign (fallback). Backwards Compatibility - All new fields are optional. Existing integrations continue to work unchanged.

```json
{"openapi":"3.1.0","info":{"title":"DM Champ API","version":"1.0.0"},"servers":[{"url":"https://api.dmchamp.com/v1","description":"Production API Server"}],"security":[{"ApiKeyAuth":[]},{"UserIdAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"query","name":"apiKey","description":"Your DM Champ API key. Obtain from Settings → API Keys."},"UserIdAuth":{"type":"apiKey","in":"query","name":"userId","description":"Your DM Champ User ID. Alternative to apiKey authentication. Cannot be used for agency-only endpoints."}},"parameters":{"ApiKeyParam":{"name":"apiKey","in":"query","description":"API key for authentication. At least one of apiKey or userId is required for protected endpoints.","required":false,"schema":{"type":"string"}}}},"paths":{"/incoming_custom_channel_message":{"post":{"summary":"Handle Custom Channel Message (Alternative)","description":"Alternative endpoint for handling incoming messages from custom channels. Same functionality as /incoming-custom-channel-message. Campaign Assignment Priority - 1. Explicit campaignId (highest priority) 2. Keyword matching (existing logic) 3. Default campaign (fallback). Backwards Compatibility - All new fields are optional. Existing integrations continue to work unchanged.","tags":["Messages"],"parameters":[{"$ref":"#/components/parameters/ApiKeyParam"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customData","messageType"],"properties":{"customData":{"type":"object","required":["body"],"properties":{"messageSid":{"type":"string","description":"Unique identifier for the message"},"id":{"type":"string","description":"Alternative unique identifier for the message"},"fromId":{"type":"string","description":"ID of the sender"},"toId":{"type":"string","description":"ID of the receiver"},"body":{"type":"string","description":"Message content"},"status":{"type":"string","description":"Message status","default":"received"},"mediaUrl":{"type":["string","null"],"description":"URL to media content (if any)"},"mediaContentType":{"type":["string","null"],"description":"MIME type of media content"},"channel":{"type":["string","null"],"description":"Custom channel identifier"},"campaignId":{"type":["string","null"],"description":"Explicit campaign ID to assign contact to (highest priority)"},"firstName":{"type":["string","null"],"description":"Contact's first name (for contact creation/update)"},"lastName":{"type":["string","null"],"description":"Contact's last name (for contact creation/update)"},"email":{"type":["string","null"],"description":"Contact's email address (for contact creation/update)"}}},"messageType":{"type":"string","description":"Type of message (e.g., text, reaction)","default":"text"}}}}}},"responses":{"200":{"description":"Message processed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"messageId":{"type":"string"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"string","description":"Additional error details"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}}}}
```

## Send Custom Channel Message

> Send an outbound message to a custom channel contact. Creates contact if it doesn't exist.

```json
{"openapi":"3.1.0","info":{"title":"DM Champ API","version":"1.0.0"},"servers":[{"url":"https://api.dmchamp.com/v1","description":"Production API Server"}],"security":[{"ApiKeyAuth":[]},{"UserIdAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"query","name":"apiKey","description":"Your DM Champ API key. Obtain from Settings → API Keys."},"UserIdAuth":{"type":"apiKey","in":"query","name":"userId","description":"Your DM Champ User ID. Alternative to apiKey authentication. Cannot be used for agency-only endpoints."}},"parameters":{"ApiKeyParam":{"name":"apiKey","in":"query","description":"API key for authentication. At least one of apiKey or userId is required for protected endpoints.","required":false,"schema":{"type":"string"}}}},"paths":{"/send-custom-channel-message":{"post":{"summary":"Send Custom Channel Message","description":"Send an outbound message to a custom channel contact. Creates contact if it doesn't exist.","tags":["Messages"],"parameters":[{"$ref":"#/components/parameters/ApiKeyParam"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customData"],"properties":{"customData":{"type":"object","required":["fromId","customChannel","body"],"properties":{"fromId":{"type":"string","description":"External ID of the contact"},"customChannel":{"type":"string","description":"Custom channel identifier"},"body":{"type":"string","description":"Message content to send"},"campaignId":{"type":["string","null"],"description":"Campaign ID to assign contact to (if creating new contact)"},"firstName":{"type":["string","null"],"description":"Contact's first name (for contact creation/update)"},"lastName":{"type":["string","null"],"description":"Contact's last name (for contact creation/update)"},"email":{"type":["string","null"],"description":"Contact's email address (for contact creation/update)"}}}}}}}},"responses":{"200":{"description":"Message sent successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"messageId":{"type":"string","description":"ID of the created message"},"contactId":{"type":"string","description":"ID of the contact"},"message":{"type":"string"}}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string","description":"Detailed error message"}}}}}}}}}}}
```

## Send Custom Channel Message (Alternative)

> Alternative endpoint for sending outbound messages to custom channel contacts. Same functionality as /send-custom-channel-message. Creates contact if it doesn't exist.

```json
{"openapi":"3.1.0","info":{"title":"DM Champ API","version":"1.0.0"},"servers":[{"url":"https://api.dmchamp.com/v1","description":"Production API Server"}],"security":[{"ApiKeyAuth":[]},{"UserIdAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"query","name":"apiKey","description":"Your DM Champ API key. Obtain from Settings → API Keys."},"UserIdAuth":{"type":"apiKey","in":"query","name":"userId","description":"Your DM Champ User ID. Alternative to apiKey authentication. Cannot be used for agency-only endpoints."}},"parameters":{"ApiKeyParam":{"name":"apiKey","in":"query","description":"API key for authentication. At least one of apiKey or userId is required for protected endpoints.","required":false,"schema":{"type":"string"}}}},"paths":{"/send_custom_channel_message":{"post":{"summary":"Send Custom Channel Message (Alternative)","description":"Alternative endpoint for sending outbound messages to custom channel contacts. Same functionality as /send-custom-channel-message. Creates contact if it doesn't exist.","tags":["Messages"],"parameters":[{"$ref":"#/components/parameters/ApiKeyParam"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customData"],"properties":{"customData":{"type":"object","required":["fromId","customChannel","body"],"properties":{"fromId":{"type":"string","description":"External ID of the contact"},"customChannel":{"type":"string","description":"Custom channel identifier"},"body":{"type":"string","description":"Message content to send"},"campaignId":{"type":["string","null"],"description":"Campaign ID to assign contact to (if creating new contact)"},"firstName":{"type":["string","null"],"description":"Contact's first name (for contact creation/update)"},"lastName":{"type":["string","null"],"description":"Contact's last name (for contact creation/update)"},"email":{"type":["string","null"],"description":"Contact's email address (for contact creation/update)"}}}}}}}},"responses":{"200":{"description":"Message sent successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"messageId":{"type":"string","description":"ID of the created message"},"contactId":{"type":"string","description":"ID of the contact"},"message":{"type":"string"}}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string","description":"Detailed error message"}}}}}}}}}}}
```

## Sync Custom Channel Message

> Syncs an externally-sent message (e.g., from GoHighLevel) back into DM Champ without re-sending it via the custom channel webhook.\
> \
> Use cases:\
> 1\. A user manually sends a message from GHL — the AI gets context of what was sent.\
> 2\. A GHL workflow sends an automated outbound message to a lead — the AI knows what was said before the lead ever replies.\
> \
> The message is stored with synced\_from\_history: true and sent\_manually: true, which prevents the outbound trigger from re-sending it to the webhook.\
> \
> If the contact doesn't exist yet and customChannel is provided, the contact is auto-created.\
> Optionally pauses the AI agent on the contact (default: true).<br>

```json
{"openapi":"3.1.0","info":{"title":"DM Champ API","version":"1.0.0"},"servers":[{"url":"https://api.dmchamp.com/v1","description":"Production API Server"}],"security":[{"ApiKeyAuth":[]},{"UserIdAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"query","name":"apiKey","description":"Your DM Champ API key. Obtain from Settings → API Keys."},"UserIdAuth":{"type":"apiKey","in":"query","name":"userId","description":"Your DM Champ User ID. Alternative to apiKey authentication. Cannot be used for agency-only endpoints."}},"parameters":{"ApiKeyParam":{"name":"apiKey","in":"query","description":"API key for authentication. At least one of apiKey or userId is required for protected endpoints.","required":false,"schema":{"type":"string"}}}},"paths":{"/sync-custom-channel-message":{"post":{"summary":"Sync Custom Channel Message","description":"Syncs an externally-sent message (e.g., from GoHighLevel) back into DM Champ without re-sending it via the custom channel webhook.\n\nUse cases:\n1. A user manually sends a message from GHL — the AI gets context of what was sent.\n2. A GHL workflow sends an automated outbound message to a lead — the AI knows what was said before the lead ever replies.\n\nThe message is stored with synced_from_history: true and sent_manually: true, which prevents the outbound trigger from re-sending it to the webhook.\n\nIf the contact doesn't exist yet and customChannel is provided, the contact is auto-created.\nOptionally pauses the AI agent on the contact (default: true).\n","tags":["Messages"],"parameters":[{"$ref":"#/components/parameters/ApiKeyParam"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customData"],"properties":{"customData":{"type":"object","required":["fromId","body"],"properties":{"fromId":{"type":"string","description":"External contact identifier (e.g., GHL contact ID)"},"body":{"type":"string","description":"Message body text"},"customChannel":{"type":"string","description":"Custom channel name (e.g., \"GoHighLevel\"). Required if contact doesn't exist yet (enables auto-creation)."},"messageSid":{"type":"string","description":"External message ID for deduplication. If a message with this ID already exists, sync is skipped."},"pauseAi":{"type":"boolean","description":"Whether to pause the AI agent on this contact. Defaults to true.","default":true},"mediaUrl":{"type":"string","description":"Optional media URL"},"mediaContentType":{"type":"string","description":"Optional media content type (e.g., \"image/jpeg\")"},"timestamp":{"type":"integer","description":"Optional timestamp in Unix milliseconds. Defaults to current time if not provided."},"firstName":{"type":"string","description":"Contact's first name (used for contact creation if contact doesn't exist yet)"},"lastName":{"type":"string","description":"Contact's last name (used for contact creation if contact doesn't exist yet)"},"email":{"type":"string","description":"Contact's email address (used for contact creation if contact doesn't exist yet)"},"campaignId":{"type":"string","description":"Campaign ID to assign (used during contact creation if contact doesn't exist yet)"}}}}}}}},"responses":{"200":{"description":"Message synced successfully (or duplicate detected)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"messageId":{"type":"string","description":"ID of the created (or existing duplicate) message"},"contactId":{"type":"string","description":"ID of the contact"},"aiPaused":{"type":"boolean","description":"Whether the AI was paused on this contact"},"contactCreated":{"type":"boolean","description":"Whether a new contact was created"},"message":{"type":"string"}}}}}},"400":{"description":"Bad request - missing required fields or API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized - invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Contact not found (and no customChannel provided for auto-creation)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string","description":"Detailed explanation with guidance"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string","description":"Detailed error message"}}}}}}}}}}}
```

## Sync Custom Channel Message (Alternative)

> Alternative endpoint for syncing externally-sent messages. Same functionality as /sync-custom-channel-message.

```json
{"openapi":"3.1.0","info":{"title":"DM Champ API","version":"1.0.0"},"servers":[{"url":"https://api.dmchamp.com/v1","description":"Production API Server"}],"security":[{"ApiKeyAuth":[]},{"UserIdAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"query","name":"apiKey","description":"Your DM Champ API key. Obtain from Settings → API Keys."},"UserIdAuth":{"type":"apiKey","in":"query","name":"userId","description":"Your DM Champ User ID. Alternative to apiKey authentication. Cannot be used for agency-only endpoints."}},"parameters":{"ApiKeyParam":{"name":"apiKey","in":"query","description":"API key for authentication. At least one of apiKey or userId is required for protected endpoints.","required":false,"schema":{"type":"string"}}}},"paths":{"/sync_custom_channel_message":{"post":{"summary":"Sync Custom Channel Message (Alternative)","description":"Alternative endpoint for syncing externally-sent messages. Same functionality as /sync-custom-channel-message.","tags":["Messages"],"parameters":[{"$ref":"#/components/parameters/ApiKeyParam"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customData"],"properties":{"customData":{"type":"object","required":["fromId","body"],"properties":{"fromId":{"type":"string","description":"External contact identifier (e.g., GHL contact ID)"},"body":{"type":"string","description":"Message body text"},"customChannel":{"type":"string","description":"Custom channel name (e.g., \"GoHighLevel\"). Required if contact doesn't exist yet."},"messageSid":{"type":"string","description":"External message ID for deduplication"},"pauseAi":{"type":"boolean","description":"Whether to pause the AI agent on this contact","default":true},"mediaUrl":{"type":"string","description":"Optional media URL"},"mediaContentType":{"type":"string","description":"Optional media content type"},"timestamp":{"type":"integer","description":"Optional timestamp in Unix milliseconds"},"firstName":{"type":"string","description":"Contact's first name (for contact creation)"},"lastName":{"type":"string","description":"Contact's last name (for contact creation)"},"email":{"type":"string","description":"Contact's email (for contact creation)"},"campaignId":{"type":"string","description":"Campaign ID (for contact creation)"}}}}}}}},"responses":{"200":{"description":"Message synced successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"messageId":{"type":"string","description":"ID of the created message"},"contactId":{"type":"string","description":"ID of the contact"},"aiPaused":{"type":"boolean","description":"Whether the AI was paused"},"contactCreated":{"type":"boolean","description":"Whether a new contact was created"},"message":{"type":"string"}}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Contact not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string","description":"Detailed error message"}}}}}}}}}}}
```
