Skip to main content

Aventora CRM ↔ Hub outbound email templates

How aventora-crm Quick Aventora / Engage by Aventora uses Engagement Hub outbound email templates configured in aventora-admin.

Audience: CRM admins, integrators, workflow authors.

Related docs:


Two different “template” concepts​

CRM Quick Aventora templatesHub outbound email templates
Where definedBuilt into CRM (aventora-message-templates.ts)aventora-admin → Account Settings → Outbound Email
PurposeBuild instruction text (phone/SMS/email brief)HTML email body + subject + branding
Placeholders{{firstName}}, meeting fields, etc.{{CUSTOMER_NAME}}, {{SUBJECT}}, {{ORGANIZATION_NAME}}, optional {{POLICY_NUMBER}}, …
StorageCRM repoHub data/email_templates/{domain}.json

They work together for email:

  1. CRM quick template → instruction (always sent).
  2. Hub layout (optional) → branded HTML + SMTP send when emailTemplateId is set.

Architecture​


Prerequisites​

LayerRequirement
AdminOutbound Email: SMTP tested, at least one email template, branding optional
HubDeployed build with email field pass-through on /integration/start and /start
CRM serverAVENTORA_BASE_URL in environment
CRM workspaceAVENTORA_API_KEY, assigned domain (Settings → Applications)
CRM userInitiator phone on profile; person has email (and name for {{CUSTOMER_NAME}})

CRM REST API​

All paths are under the CRM API host (same origin as the CRM app in typical deployments). Authenticate with the workspace member JWT used for other Aventora REST calls.

GET /rest/aventora/email-templates​

Lists Hub layouts for the workspace domain.

Response:

{
"templates": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Policy renewal",
"subjectTemplate": "Your policy renewal — {{SUBJECT}}",
"customPlaceholderKeys": ["POLICY_NUMBER", "RENEWAL_DATE"]
}
]
}
  • customPlaceholderKeys — placeholders found in subject/body excluding SUBJECT, CUSTOMER_NAME, ORGANIZATION_NAME.
  • Empty templates — often means SMTP/email not configured for the domain on Hub.

POST /rest/aventora/start-engagement​

When channel is email and type is informational:

FieldMaps to HubPurpose
personIdsource_record_idPerson UUID
contactIdentifierrecipientEmail address
instructioninstructionBrief (required unless emailBodyHtml or a Hub template is provided)
clientNameclient_name{{CUSTOMER_NAME}} (optional; server uses person name if omitted)
emailSubjectemail_subjectSubject + {{SUBJECT}}. Optional: Hub writes one from the engagement if omitted.
emailBodyHtmlemail_body_htmlFull HTML document (mutually exclusive with template id/name). Hub does not wrap branding around it. Aliases: htmlBody, html_body, email_body_html.
emailTemplateIdemail_template_idHub template UUID
emailTemplateNameemail_template_nameAlternative to id
emailTemplateParamsemail_template_paramse.g. { "policy_number": "POL-99" } → {{POLICY_NUMBER}}

The CRM server also sends Hub from_name (optional REST fromName / from_name, otherwise the sending user's Settings → Profile first + last name, otherwise the default initiator Profile name, otherwise that initiator's CRM user account first + last name, otherwise the workspace display name). REST start/bulk keep the caller's Profile name even though person load uses system auth. That is the From display name for this send and overrides Hub Account Settings From Name. If CRM cannot resolve a name, Hub keeps its usual From Name / linked-mailbox name / platform EMAIL_DISPLAY_NAME.

Example:

{
"personId": "uuid-of-person",
"channel": "email",
"type": "informational",
"instruction": "Policy renewal reminder",
"contactIdentifier": "customer@example.com",
"clientName": "Alex Morgan",
"emailSubject": "Your policy renewal",
"emailTemplateId": "550e8400-e29b-41d4-a716-446655440000",
"emailTemplateParams": {
"policy_number": "POL-2026-8842",
"renewal_date": "June 15, 2026"
}
}

Hub also accepts the same fields on POST /integration/start and POST /start (snake_case) for non-CRM integrators.

GET /rest/aventora/person-views​

Lists Person views the caller can see in the workspace (workspace-shared views for API keys; plus the member’s unlisted views when using a user JWT).

Response:

{
"views": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Policy renewals",
"type": "TABLE",
"visibility": "WORKSPACE"
}
]
}

Use a returned id as viewId on bulk start. The CRM applies that view’s filters at send time (current matching People, not a snapshot).

POST /rest/aventora/start-engagement-bulk​

Same email fields as start-engagement, including optional fromName / from_name and htmlBody / emailBodyHtml. Recipients are exactly one of: an explicit list, every eligible Person, or a Person view — never combine them.

RecipientsBody
Some contactspersonIds: array of Person UUIDs (max 1000)
All contacts"audience": "all" (do not send personIds or viewId)
Person viewviewId: UUID from GET /rest/aventora/person-views (optional "audience": "view")

Missing personIds does not mean all. CRM loads People (from the ids, the whole workspace, or the view filters), skips do not contact and missing email (for channel: "email"), chunks Hub submits at 1000 rows, and returns aggregated counts. View audiences are not capped at 1000 People — CRM pages and chunks like audience: "all".

All-contacts example:

{
"audience": "all",
"channel": "email",
"type": "informational",
"emailSubject": "Your policy renewal",
"emailBodyHtml": "<p>Dear {{CUSTOMER_NAME}},</p><p>Policy reminder.</p>"
}

Some-contacts example:

{
"personIds": ["uuid-1", "uuid-2"],
"channel": "email",
"type": "informational",
"emailSubject": "Your policy renewal",
"emailTemplateId": "550e8400-e29b-41d4-a716-446655440000",
"emailTemplateParams": {
"policy_number": "POL-2026-8842"
}
}

Person-view example:

{
"viewId": "550e8400-e29b-41d4-a716-446655440000",
"channel": "email",
"type": "informational",
"emailSubject": "Your policy renewal",
"emailTemplateId": "550e8400-e29b-41d4-a716-446655440000",
"emailTemplateParams": {
"policy_number": "POL-2026-8842"
}
}

Response:

{
"batchId": "batch-1",
"batchIds": ["batch-1", "batch-2"],
"matchedCount": 1502,
"queuedCount": 1480,
"skippedCount": 22,
"errors": ["uuid-dnc: do not contact"]
}
  • batchId — first Hub batch (backward compatible).
  • batchIds — one id per Hub chunk when the audience is larger than 1000.
  • matchedCount — People considered (personIds length, all People for audience: "all", or People matching viewId).
  • skippedCount — CRM skips (do not contact / missing email) plus Hub skips.

Do not send emailBodyHtml together with emailTemplateId / emailTemplateName.

emailBodyHtml is the full HTML document Hub sends (after {{PLACEHOLDER}} fill). Hub templates (emailTemplateId / emailTemplateName) still use account branding wrap.

Integration context (alternative)​

{
"phone_number": "customer@example.com",
"domain_name": "aventora",
"source_record_id": "...",
"source_org_id": "...",
"channel": "email",
"type": "informational",
"instruction": "...",
"context": {
"email_template_id": "...",
"email_template_params": { "policy_number": "POL-99" }
}
}

Quick Aventora UI (shipped)​

When Channel = Email in Engage by Aventora:

  1. Email layout (Engagement Hub) — dropdown from GET /rest/aventora/email-templates.
  2. Email subject — required when a layout is selected.
  3. Template fields — one input per customPlaceholderKey.
  4. Instruction — from CRM quick template (unchanged).

Optional developer mapping on CRM quick templates (aventora-message-templates.ts):

  • hubEmailTemplateName — pre-select Hub layout by name when templates load.
  • defaultEmailSubject — initial subject when pre-selecting.

Without a layout, send still works (instruction-only / Hub LLM path). See Outbound Email send paths.


Configuration​

CRM server​

VariableRequiredDescription
AVENTORA_BASE_URLYesHub base URL (e.g. https://hub.example.com)

CRM workspace (UI)​

Application variableRequiredDescription
AVENTORA_API_KEYYesAccount Hub API key
Assigned domainYesDomain slug for Hub

CRM frontend (optional)​

VariableDefault
REACT_APP_AVENTORA_EMAIL_TEMPLATES_ENDPOINT{REACT_APP_SERVER_BASE_URL}/rest/aventora/email-templates
REACT_APP_AVENTORA_START_ENDPOINT{SERVER}/rest/aventora/start-engagement

Override these only in local development. In production the CRM injects the server base URL automatically — leave email-templates unset to use the default path on the same host.


Workflows​

Built-in CRM workflow actions (preferred):

  1. Send Email (Engagement Hub) — informational email for a Person (personId + subject/body or Hub template). Executes Hub POST /integration/start with channel=email and type=informational.
  2. Aventora Engagement / Bulk Engagement — phone, SMS, or email with a Cockpit action type dropdown and a multiline Instruction prefilled from that action (editable); when channel is Email, configure subject, HTML body, or Hub layout template (same fields as Engage by Aventora).

Advanced / custom HTTP (still supported):

  1. HTTP request step → POST {CRM_SERVER}/rest/aventora/start-engagement with person id from trigger + email fields above.
  2. Map workflow variables into emailTemplateParams.
  3. Confirm Aventora CRM workflow auth can call workspace REST (Bearer token model).

Sender for all Hub email paths is Engagement Hub → Outbound Email (System SMTP, Google, or Microsoft)—not CRM connected-account Gmail send scopes.


Troubleshooting​

SymptomCheck
Layout dropdown emptyAdmin Outbound Email + SMTP; workspace API key and domain
403 on list/startAVENTORA_API_KEY, AVENTORA_BASE_URL, APP_SECRET if key is encrypted
Layout selected, send failsHub logs; template id exists; all template fields filled
Wrong customer namePerson name on record; or pass clientName explicitly
Placeholder not replacedUse {{UPPER_SNAKE}} in Hub template; pass snake_case keys in emailTemplateParams
Person-views list emptyCreate a workspace-visible People view in CRM; API keys do not see unlisted/personal views
viewId send failsConfirm the id is from GET /rest/aventora/person-views; view must be on Person, not Company

Documentation map​

DocContent
Engagement Hub Start APICanonical client guide — /integration/start, /start, email_body_html
Outbound EmailHub email internals, placeholders, branding
Aventora User ManualEnd-user Engage + Admin setup
This fileCRM REST + UI + config
Aventora CRM ↔ HubEngagements, pause, webhooks

Deploy order​

  1. Aventora-Assistant — /integration/start + /start email fields, email_address for email channel.
  2. aventora-crm — GET /rest/aventora/email-templates, GET /rest/aventora/person-views, start-engagement pass-through, Engage UI, workflow Send Email (Engagement Hub) + Start Engagement email fields.
  3. aventora-admin — template authoring (unchanged; source of truth).

Changelog​

DateChange
2026-09-28Email photos: Engage, Quick engage, and Bulk engage can attach images when the channel is email. CRM sends emailAttachments. Hub stores bulk images once on the batch and attaches them to each email.
2026-09-21Partner bulk From + htmlBody: POST /rest/aventora/start-engagement-bulk keeps the CRM user/Profile From name through REST system auth, falls back to the default initiator's CRM user account name, and accepts Laravel htmlBody / html_body as emailBodyHtml.
2026-09-19Partner bulk From name: API-key POST /rest/aventora/start-engagement-bulk now falls back to workspace display name and optional fromName / from_name. CRM also sends campaign-level Hub from_name.
2026-09-18Bulk From display name: Partner POST /rest/aventora/start-engagement-bulk and UI bulk email now keep the CRM From name (from_name) through Hub ingest. Recipients see the same Profile / default-initiator name as a single Engage send.
2026-09-16Hub reply copy: Appointment-booking email looks up the next available slots when the customer asks for a time, and signs off with the organization name. System/SES omits CID logos; platform SMTP includes a plain-text alternative.
2026-09-16Subject from the engagement: If emailSubject / email_subject is omitted, Hub writes the inbox subject from the instruction and engagement type. Header/footer branding is unchanged.
2026-09-16From display name: CRM-originated email sends from_name (workspace member full name). Hub uses it as the From display name for that send.
2026-09-14Inline HTML is the full document: CRM emailBodyHtml / Hub email_body_html is sent as the complete message (styles and layout included). Hub no longer wraps it in account branding. Bulk replay now copies that HTML onto POST /start. Hub templates still use branding wrap.
2026-08-23Person view audience: GET /rest/aventora/person-views lists Person views. POST /rest/aventora/start-engagement-bulk accepts viewId (mutually exclusive with personIds and "audience": "all"). CRM applies the view filters at send time, skips do-not-contact / missing email, and chunks Hub submits at 1000.
2026-08-20Bulk email to all contacts: POST /rest/aventora/start-engagement-bulk accepts "audience": "all" (mutually exclusive with personIds). CRM resolves People, skips do-not-contact / missing email, and chunks Hub submits at 1000. REST start/bulk action pass emailBodyHtml through to Hub.
2026-08-17Aventora Engagement / Bulk Engagement workflow steps use a cockpit action type dropdown and a multiline instruction field prefilled from the selected action.
2026-07-31Documented built-in workflow actions for Hub informational email (Send Email + Start/Bulk Engagement email fields).