salesintermediate12 min setupby Mantle

Welcome e-mail for a new HubSpot contact

When a contact is created in HubSpot, read it back and send a personalised welcome e-mail.

Contact createdRead the contactSend the welcome

Drag to pan, pinch to zoom. This is the real graph the template installs.

Purpose

When a contact is created in HubSpot, read it back and send a personalised welcome e-mail.

How it works

What it does

  • Subscribes to HubSpot's contact.creation event.
  • Reads the new contact back so the e-mail has real properties rather than just an id.
  • Sends a personalised welcome.

Validation

This template is contract-validated: the unit suite checks every node type, every config key and the whole graph against the same rules a saved workflow passes. It has not been run against the live provider — the ids, names and columns below are placeholders to replace with your own.

Nodes 3

  1. 01Contact createdtrigger.hubspot_eventTrigger
  2. 02Read the contacthubspot.get_contactApp
  3. 03Send the welcomemail.sendDestination
View template JSON
{
  "format": "mantle-workflow/v1",
  "id": "hubspot-new-contact-welcome",
  "name": "Welcome e-mail for a new HubSpot contact",
  "graph": {
    "nodes": [
      {
        "id": "event",
        "type": "trigger.hubspot_event",
        "label": "Contact created",
        "config": {
          "app_id": "0000000",
          "subscription_types": [
            "contact.creation"
          ],
          "max_concurrent_requests": 10
        },
        "worker_type": "generic-worker",
        "position": {
          "x": 60,
          "y": 220
        }
      },
      {
        "id": "contact",
        "type": "hubspot.get_contact",
        "label": "Read the contact",
        "config": {
          "contact_id": "{{ $json.objectId }}",
          "properties": "email,firstname,lastname,company"
        },
        "worker_type": "generic-worker",
        "position": {
          "x": 380,
          "y": 220
        }
      },
      {
        "id": "welcome",
        "type": "mail.send",
        "label": "Send the welcome",
        "config": {
          "to": "{{ steps.contact.properties.email }}",
          "subject": "Welcome, {{ steps.contact.properties.firstname }}",
          "body_text": "Hi {{ steps.contact.properties.firstname }},\n\nThanks for getting in touch. Someone from the team will follow up shortly.\n"
        },
        "worker_type": "generic-worker",
        "position": {
          "x": 700,
          "y": 220
        }
      }
    ],
    "edges": [
      {
        "from": "event",
        "to": "contact"
      },
      {
        "from": "contact",
        "to": "welcome"
      }
    ]
  }
}

Requirements

The connections and permissions each step needs, from the node contracts in the catalog.

  • HubSpotBearer token

    Used by Contact created, Read the contact.

    Credential: {"token", "developer_api_key", "client_secret"} · the HubSpot private-app token, or {"token": "…"}

    • The webhooks API authenticates with the developer API key of the account that owns the app, and signatures are verified with the app's client secret. The private-app token alone cannot do either.
    • HubSpot's webhook target URL is a single app-level setting, so one HubSpot app backs one published workflow. Publishing a second workflow against the same app_id fails rather than stealing the first one's events.
    • One app serves every HubSpot account that installed it: branch on portalId when more than one portal is in play.
    • Filtering is done by HubSpot — subscription_types and property_name decide what is ever sent, so nothing arrives here to be discarded.
    • Runs are deduplicated per portal, subscription, object, occurredAt and eventId together — HubSpot does not guarantee eventId is unique — so a delivery retried up to ten times over twenty-four hours starts one run.
    • Deliveries must be answered within five seconds, which is why the run is accepted and executed asynchronously.
  • SendGridAPI key

    Used by Send the welcome.

    Credential: {"api_key"} or {"username", "password"}

Setup

  • app_id is your HubSpot developer app id — the webhooks API belongs to the app, not the portal.
  • The HubSpot connection needs developer_api_key and client_secret as well as the private-app token: the key creates the subscription and the secret verifies the signature.
  • Pick a mail connection on Send the welcome and edit the copy.

Sample input and output

Synthetic examples: node-contract samples or placeholders, never customer data.

Input

What the Contact created trigger receives, as its node contract samples it.

{
  "appId": "",
  "attemptNumber": 0,
  "changeSource": "",
  "eventAction": "propertyChange",
  "eventId": "1",
  "objectId": "12345",
  "objectType": "contact",
  "occurredAt": 0,
  "occurredAtIso": "",
  "portalId": "62515",
  "propertyName": "email",
  "propertyValue": "ada@example.com",
  "subscriptionId": "",
  "subscriptionType": "contact.propertyChange"
}

Output

Send the welcome mail.send

{
  "body": null,
  "message_id": "",
  "provider": "",
  "sent": true,
  "status_code": 0,
  "thread_id": ""
}

Failure handling

What the graph does when a step fails, read from its retry settings, error branches and error policies.

  • A step that fails, after any retries, fails the run. The failed step is kept with its input and error.

See it run, then make it yours.

Templates install as drafts. Edit any step, and Workflow Health re-checks the graph on every save.