App event triggers
Reference for the HubSpot and Airwallex event triggers, the event names a workflow can listen for and the payload each event delivers.
An app event trigger starts a run when a connected app reports a change, such as a deal moving stage in HubSpot or a deposit settling in Airwallex. It is a provider-specific form of the webhook trigger: the event arrives on the provider's inbound route, Loopfour turns it into a standard envelope, and every active workflow whose trigger matches gets one run.
How an event reaches a workflow
- The provider posts to
POST /webhooks/hubspotorPOST /webhooks/airwallexon the API host. - Loopfour checks the signature. A bad signature gets
401and no run starts. - Loopfour reads the provider account from the event (the HubSpot
portalId, or the Airwallexaccount_id) and looks for a connection with that account. If no connection has it, the event is dropped. - The event is turned into the envelope below and matched against the triggers of the active workflows in the company that owns the connection.
- Each matching workflow starts one run, recorded with
triggerType: "webhook".
The route answers 200 with {"received": true, "count": <events accepted>} once it has processed the batch. Other answers are 400 for a body it cannot parse, 404 for an unknown provider and 500 when verification itself fails.
The event envelope
Both providers deliver the same envelope. In the run input it sits at input.webhookEvent.payload.
| Field | Meaning |
|---|---|
id | Loopfour's ID for this event |
provider | hubspot or airwallex |
eventType | The provider event name, such as deal.propertyChange |
occurredAt | When the event happened, as an ISO 8601 timestamp |
externalAccountId | The provider account the event belongs to |
externalEventId | The provider's own event ID |
data | The event details. The fields depend on the provider and event |
raw | The original provider payload, unchanged |
So a step reads the HubSpot record ID as {{input.webhookEvent.payload.data.objectId}} and the event name as {{input.webhookEvent.eventType}}. See Variable references for the rest of the reference syntax.
HubSpot
Configuration
{
"trigger": {
"type": "hubspot_event",
"eventKind": "deal.propertyChange",
"propertyName": "dealstage",
"filter": { "data.propertyValue": { "$eq": "closedwon" } }
}
}| Field | Type | Required | Meaning |
|---|---|---|---|
type | "hubspot_event" | Yes | |
eventKind | string | Yes | The event to listen for. See the table below |
propertyName | string | No | For *.propertyChange events only: the HubSpot property that must have changed |
filter | object | No | Extra conditions on the envelope. See Filters |
In Studio, add a HubSpot block and switch it to trigger mode. The block shows Event, Filter (JSON) and, for property-change events, Property Name.
Events
| Object | eventKind values |
|---|---|
| Contact | contact.creation, contact.deletion, contact.merge, contact.restore, contact.privacyDeletion, contact.propertyChange |
| Company | company.creation, company.deletion, company.merge, company.restore, company.propertyChange |
| Deal | deal.creation, deal.deletion, deal.merge, deal.restore, deal.propertyChange |
| Ticket | ticket.creation, ticket.deletion, ticket.merge, ticket.restore, ticket.propertyChange |
| Conversation | conversation.creation, conversation.deletion, conversation.newMessage, conversation.privacyDeletion, conversation.propertyChange |
| Quote | quote.creation, quote.propertyChange, quote.published |
Matching rules:
- An exact value such as
deal.creationmatches only that event. - A prefix such as
deal.*matches every event for that object. *matches every HubSpot event.quote.publishedis a Loopfour shortcut. It matches aquote.propertyChangeevent wherehs_statuschanges toAPPROVED,APPROVAL_NOT_NEEDEDorPUBLISHED.
Event data
Every HubSpot event carries these fields in data:
| Field | Type |
|---|---|
objectId | number |
objectTypeId | string |
portalId | number |
subscriptionId | number |
subscriptionType | string |
changeSource | string |
changeFlag | string |
sourceId | string |
attemptNumber | number |
Property-change events add propertyName and propertyValue. Merge events add mergedObjectIds, newObjectId and numberOfPropertiesMoved.
The event tells you which record changed, not the whole record. To get the deal amount or the contact's email, add a HubSpot step that fetches the record by {{input.webhookEvent.payload.data.objectId}}.
Subscriptions
The HubSpot events Loopfour receives are set in Loopfour's HubSpot app, not per connection. Connecting HubSpot is enough; you do not register a webhook URL in HubSpot yourself.
Airwallex
Configuration
{
"trigger": {
"type": "airwallex_event",
"selectedTriggerId": "deposit.settled",
"filter": { "currency": { "$in": ["USD", "EUR"] } }
}
}| Field | Type | Required | Meaning |
|---|---|---|---|
type | "airwallex_event" | Yes | |
selectedTriggerId | string | Yes | The event to listen for. Must equal the event name exactly |
filter | object | No | Extra conditions on the event data. See Filters |
In Studio, add the Airwallex block from the Triggers group. It shows Event and Advanced JSON filter (optional).
Events
selectedTriggerId | When it fires |
|---|---|
payment_attempt.paid | A payment attempt is paid |
payment_attempt.settled | A payment attempt is settled |
deposit.pending | A deposit is pending |
deposit.settled | A deposit is settled |
There is no wildcard. To react to more than one event, use one workflow per event.
Event data
data holds the Airwallex event's data.object: the payment attempt or deposit itself. externalAccountId is the Airwallex account_id. The full event, including its name and created_at, is in raw.
Subscriptions
Airwallex webhook subscriptions are set in the Airwallex dashboard. Loopfour does not create them when you connect.
Filters
A filter is a JSON object. Each key is a dot path and each value is either a plain value (must be equal) or an operator object. All keys must pass.
| Operator | Passes when |
|---|---|
$eq | The value equals this |
$ne | The value does not equal this |
$in | The value is in this array |
$exists | true: the path has a value. false: it has none |
The paths start from a different place for each provider:
- HubSpot: paths start at the envelope, so write
data.propertyValueoreventType. - Airwallex: paths start inside
data, so writecurrencyoramount.
In Studio, the HubSpot Filter (JSON) placeholder shows propertyName without the data. prefix. A filter written that way does not match, because HubSpot filter paths start at the envelope. Write data.propertyName, or use the Property Name field.
Repeated events
Providers resend events they think were not delivered. Each delivery can start a new run. Use externalEventId to spot a repeat, for example by checking it against a record your workflow writes, and make the steps safe to run twice.
Test without the provider
Start the workflow by hand with the envelope as input. See Run any workflow on demand for the request; put the envelope fields from this page under webhookEvent.payload.
Inbound email trigger
Start a workflow from inbound email: the address format, the payload a run receives and how attachments are passed to later steps.
Slack triggers
Start a workflow from Slack events, slash commands or interactions, and read the payload each Slack trigger passes into the workflow run.
Loopfour