Webhook Forwarding
The Webhook Forwarding feature is designed to make it easy to for ISVs to obtain near real time events whenever important data changes in a Third Party App or whenever specific user events occur.
Example Scenario
Let's say you want to receive an event every time your end users create a new lead in their CRM. For the purpose of this tutorial, we'll use Salesforce CRM as an example. With Webhook Forwarding, you can subscribe to these events – even when the underlying application doesn't support webhookd.
How it Works
Webhook forwarding relies on a critical part of the Alloy Unified API: polling and real time webhooks. Behind the scenes, Alloy leverages an advanced system of realtime webhook subscriptions and periodic polling to ensure the data we cache is continuously up to date.
When an end user makes their first connection, Alloy Unified API subscribes to all relevant webhooks. We also spin up a 12 hour polling sync to reconcile any dropped events (note: this polling frequency can be adjusted to be even more real time, talk to your account rep if you'd like to explore this).
Taking a look at our example, Salesforce CRM, this app does not natively expose webhooks via an API. In other words, unlike other CRMs like Hubspot, Alloy Unified API does not have webhooks to subscribe to automatically. To remedy this, Alloy performs regular polling to check for changes in Salesforce. Using Webhook Forwarding, you can subscribe to these events using APIs.
Implementation
Setting up Webhook Forwarding
To subscribe to events using Webhook Forwarding, you'll need an address that can receive and process webhooks. This address should be a POST endpoint capable of handling incoming body data. You'll also need to specific the events, or topic
to subscribe to.
If you're just testing, we recommend using ngrok to get set up. You can spin up a simple express app in minutes and mirror it to the internet.
Take a look at the example below:
curl --location 'https://embedded.runalloy.com/2023-12/one/webhooks' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{YOUR_API_KEY}}' \
--header 'Content-Type: application/json' \
--data '{
"address": "{{YOUR_WEBHOOK_ADDRESS}}",
"topic": [
"crm/accounts",
"crm/contacts",
"crm/leads",
"crm/notes",
"crm/opportunities",
"crm/stages",
"crm/tasks",
"crm/users"
]
}'
Parameters Explained
address
: The URL of the endpoint that will be receiving the events. We strongly advise using HTTPS.topic
: An array of events to subscribe to. A full list can be found here.
There are two types of topics you can subscribe to: System events and Data Changed events. System events let you subscribe to user-driven actions such as whenever a user makes a new connection. Data changed events alert you every time data is modified in a Third Party App such as Salesforce CRM.
Response Data
When receiving an webhook using Webhook Forwarding, you'll get data structured as follows. A non-exhaustive description of the most important values is provided below:
Header Data
x-alloy-signature
: The RSA signature associated with this request. Intended to avoid request spoofing.x-alloy-topic
: The name of the topic associated with this event
{
"host": "{{YOUR_WEBHOOK_ADDRESS}}",
"user-agent": "axios/1.6.2",
"content-length": "928",
"accept": "application/json, text/plain, */*",
"accept-encoding": "gzip, compress, deflate, br",
"content-type": "application/json",
"x-alloy-signature": "f722a226a1d611ee8c900242ac120002...",
"x-alloy-topic": "commerce/orders",
"x-forwarded-for": "02.0020.2699.923",
"x-forwarded-host": "{{YOUR_WEBHOOK_ADDRESS}}",
"x-forwarded-proto": "https"
}
Body Data
updateType
: Returns the type of event forwarded. If Data Changed, this will return eithercreated
,updated
, ordeleted
connectionId
: The connectionId associated with this eventuserId
: The userId associated with this eventdataPayload
: The JSON data for the event. Note that this is structured in the Unified model and does not come through as raw data.category
: The category of the app you subscribed to.name
The display name of the app where this event is coming from.eventTimestamp
The date stamp when the event occurred.
{
connectionId: '65874bebc8100057bf8c2ee8',
userId: '65874bef602dc2e74d26d9fa',
updateType: 'updated',
dataPayload: {
remoteId: '0000019375',
createdTimestamp: 1678093506,
updatedTimestamp: 1678093506,
orderNumber: '0000019375',
totalShipping: 4.95,
totalTax: 12.39,
totalPrice: 66.91,
currency: 'USD',
lineItems: [ [Object] ],
orderStatus: 'new',
paymentStatus: 'not_paid',
billingAddress: {
address1: '43 Main Rd.',
address2: '',
city: 'New York',
postalCode: '',
region: '',
countryCode: '',
firstName: 'Jane',
lastName: 'Doe',
phone: ''
},
customer: {
customerId: '65874bf90eb1e288406fd2ab',
email: '',
firstName: 'Jane',
lastName: 'Doe',
phone: ''
},
id: '9b113ba8-20d7-4624-99bb-7e90522a6c5e'
},
category: 'commerce',
name: 'Salesforce CommerceCloud',
userName: "Gregg's Account",
eventTimestamp: '2023-12-22T10:23:34Z'
}