How to send attendee data to HubSpot using Structured JSON Payload
This guide explains how to configure idloom's Structured JSON Payload mode to create HubSpot contacts from attendee registrations — covering OAuth2 setup, webhook configuration, and JSON template syntax.
HubSpot expects a specific JSON envelope when you create a contact via its API. idloom's flat field mapping produces a different structure. Structured JSON Payload mode bridges that gap: you write a JSON template that matches exactly what HubSpot expects, drop {{placeholders}} where the attendee data goes, and idloom resolves them at send time.
What you need before you start
- An idloom account with access to Manager → Integration.
- A HubSpot account with a private app (or OAuth app) that has the crm.objects.contacts.write scope granted.
- The OAuth2 credentials for that app: Client ID, Client Secret, and a valid Refresh token.
Step 1 — Create the integration
In your idloom workspace, go to Manager → Integration → Idloom and click to add a new integration. A catalogue appears listing the available integration types. Under Most used, select API & Webhooks ("Automate workflows using APIs and webhooks") and click Add. You are then taken to the integration configuration screen where you can give it a recognisable name (for example HubSpot). On the same screen, toggle Structured JSON payload on. The flat Fields mapping editor is replaced by a JSON editor — that is where the template goes.
> Why toggle Structured JSON payload on here? HubSpot's Contacts API expects the attendee data nested under a "properties" key. The flat Fields mapping mode produces a different shape and cannot produce that nesting. Structured JSON Payload mode gives you full control over the output envelope.
Step 2 — Configure OAuth2 authentication
HubSpot uses OAuth2 to authorise API calls. Rather than hard-coding a short-lived access token, idloom can request a fresh one automatically using a refresh token.
In the integration, open the Authentication section and create a new authentication named Hubspot v1 (or any name you will recognise later). Fill in the fields as follows:
| Field | Value |
|---|---|
| Type | OAuth2 authorization code |
| Client ID | Your HubSpot app's Client ID |
| Client secret | Your HubSpot app's Client secret |
| Token URL | https://api.hubapi.com/oauth/v1/token |
| Use refresh token | ✅ Checked |
| Refresh token | Your HubSpot refresh token |
| Scope | Leave empty — scope is already encoded in the refresh token's granted permissions |
Save the authentication. idloom will exchange the refresh token for a valid access token automatically on every webhook call, so no manual token rotation is needed.
Step 3 — Write the JSON payload template
In the integration's JSON editor, enter the following template:
{
"attendee": {
"properties": {
"email": "{{email}}",
"firstname": "{{firstname}}",
"lastname": "{{lastname}}"
}
}
}
This is the minimum required to create a HubSpot contact. The "attendee" top-level key tells idloom which section of the template to use when a guest.* webhook fires. The "properties" wrapper is what HubSpot's CRM v3 Contacts API expects at the root of every contact creation request. The three placeholders — {{email}}, {{firstname}}, {{lastname}} — are standard attendee registration form fields and resolve automatically for every attendee record.
> Tip — exploring all available placeholders: if you want to see every attendee field available before trimming down to what you need, click the Load defaults button above the editor and select Attendee. idloom pre-fills the editor with a complete reference template. Edit or trim the result as needed. This is useful when you want to send additional fields to HubSpot later (job title, company name, phone number, and so on).
> Why "Without wrapping" matters: by default, idloom wraps every webhook payload in a "data" envelope. HubSpot's API does not expect that wrapper — the "properties" object must be at the root of the request body. Always check Without wrapping when the target system expects a clean root-level JSON object.
Step 4 — Set up a test webhook before going live
Before configuring the real HubSpot endpoint, it is worth verifying that the payload resolves correctly. The cleanest way to do this is a guest.manual webhook pointing to webhook.site.
In the integration, add a new webhook with these settings:
| Field | Value |
|---|---|
| Event | guest.manual |
| Name | validation (or any test name) |
| Authentication | No authentication flow |
| URL | Your webhook.site URL |
| Method | POST |
| Resource class | Structured JSON Payload |
| Without wrapping | ✅ Checked |
| Active | ✅ Checked |
The guest.manual event type is what makes this useful for testing: it adds a named entry to the More actions menu on every attendee detail page. Open any attendee record, click the gear icon (More actions), and you will see validation listed. Click it to fire the webhook on demand — no new registration needed, no side effects, repeatable as many times as you like. Check webhook.site to confirm the resolved payload looks exactly as expected before proceeding.
Step 5 — Configure the live HubSpot webhook
Once the test payload looks correct, add the production webhook:
| Field | Value |
|---|---|
| Event | guest.created (or guest.updated, or both — see note below) |
| Name | Send to Hubspot |
| Authentication | Hubspot v1 (OAuth2 authorization code) |
| URL | https://api.hubapi.com/crm/v3/objects/contacts |
| Method | POST |
| Resource class | Structured JSON Payload |
| Without wrapping | ✅ Checked |
| Active | ✅ Checked |
> Which event to use: guest.created fires once, when the attendee first registers — the right choice if you want to create a new HubSpot contact per registration. guest.updated fires every time an attendee record changes — useful if you also want to keep the contact in sync when an attendee modifies their registration. Add both as separate webhooks if you need both behaviours. During setup and testing, guest.manual (as used in step 4) gives you a trigger you control completely from the attendee detail page.
What happens when the webhook fires
When the configured event fires (or when you trigger guest.manual manually from the attendee detail page), idloom:
- Resolves the three {{placeholders}} against the current attendee record.
- Sends the resolved JSON to https://api.hubapi.com/crm/v3/objects/contacts via POST.
- Attaches a valid Bearer token obtained automatically from HubSpot using the stored refresh token.
HubSpot receives a clean POST body:
{
"properties": {
"email": "kristina.weber@example.com",
"firstname": "Kristina",
"lastname": "Weber"
}
}
If the call succeeds, HubSpot creates (or updates, depending on your HubSpot deduplication settings) a contact with those three properties. The contact appears in HubSpot immediately.
Extending the template
The three-field template above is the minimum. HubSpot contacts support many more standard properties, all of which map to attendee fields available in idloom. Common extensions:
{
"attendee": {
"properties": {
"email": "{{email}}",
"firstname": "{{firstname}}",
"lastname": "{{lastname}}",
"jobtitle": "{{job_title}}",
"phone": "{{phone}}",
"company": "{{cpy_name}}",
"city": "{{cpy_city}}",
"country": "{{cpy_country}}"
}
}
}
For custom registration form fields added to your event form, use the field's internal name as the placeholder (for example {{dietary_preferences}}). The internal name is visible in the idloom form builder — do not use the display label, which is not resolved.