Bots, Hooks, and Extensions
When you are building a modern application, it is only a matter of time before your customers ask for integrations with other systems. Listen to them, and your acquisition and retention will benefit. This post provides a way to frame this space and identifies the set of technical challenges you will need to think about and solve to add a robust integration story to your app.
Benefits of integrations in your app
Over 90% of SaaS product leaders say that having integration features embedded in their application increases acquisition and retention.
We live in a world where an average mid-size company uses close to 140 SaaS products. Very few of them make sense in isolation, they all support parts of a bigger business process, which is only possible if they are integrated. The newsletter signups from Pipedrive must flow as leads to Salesforce. Weekly sales numbers from Salesforce must be sent to Slack as a report, etc.
Customers of SaaS products are increasingly comparing alternative solutions using integration capabilities as the key differentiator. In a crowded space, the integration features of your app can make a difference between closing or losing a deal. Integrations in your app are no longer a checkbox on your customer’s checklist. Showing a logo is not sufficient. Your integration story must have a quality and depth to it to win.
Integrations are also key to retaining your customers longer. An average mid-size company changes 39% of their SaaS application stack every year. It is much easier for your customer to replace a disconnected or poorly connected application than to remove an application that has its integration tentacles deeply embedded in several other systems in the customer’s ecosystem.
Making the right technical choices when deciding on the scope and approach to the integration story in your app is key. The rest of this post frames the space and provides an overview of the technical challenges you will need to address along the way.
Bots, hooks, extensions - choosing the right integration pattern
Integration capabilities come with different names, but they really revolve around a handful of integration patterns. One useful way of categorizing them is to look at the trigger of the integration behavior. Looking from the perspective of your app, there are outgoing, incoming, or scheduled integrations, or a combination thereof. We will look into each of these in turn.
In an outgoing integration, your application generates an event that must trigger some action in an external system of your customer. For example, when a new order is created in your application, you need to send a notification to your customer’s Slack workspace or copy that order over to your customer’s Salesforce instance.
A solution to this seemingly simple integration scenario can quickly snowball into a complex technical problem. Here are some aspects you will need to consider:
- Authentication and authorization: Assuming your application is multi-tenant, each of your tenants will want to bring their own instance of the external system, for example, Salesforce. This will require you to provide a way for your tenants to authorize access to the external system. You will need to store this information in a database, separately for each tenant and each target system you want to integrate with. You will also need to monitor the credentials for expiry and validity and either refresh them or ask the tenant for re-authorization if they are no longer valid.
- Identity mapping: You will need to be able to map tenants of your application onto users/tenants of the external system (separately for each external system) so that an event generated by a specific tenant of your application can be delivered to the external system that the tenant actually owns.
- Throttling: As your app calls the external system, you will need to observe any throttling limits that the system enforces. You will need to understand the specific quotas and their scope (is it per-tenant, per IP, or something else).
- Retries: You need to decide how to behave when the call to the external system fails. Such failure can be the result of the system being down, undergoing regular maintenance, or your call rate has exceeded the limits. You need to handle HTTP 429 Retry-After responses properly. You need to consider how to behave in response to HTTP 5xx errors returned from the external system.
With an incoming integration, your application may receive notifications of an event that occurred in an external system of your customer. For example, when a new order was created in the Salesforce instance of your customer, your app can be notified to create a shipping label. Or, one of your users typed a question in their Slack workspace that is sent to your application for processing.
The incoming integration scenario has more nuances and technical challenges to address than the outgoing integration:
- Authentication, authorization, and webhook registration: Similar to the outgoing scenario, each of your tenants must authenticate and authorize your access to their instance of the external app, and you need to store and monitor this information. In addition, you will need to understand how to register with the external app to get notified when certain events occur. Technically this usually takes the form of registering a webhook in the external app. However, there is no standard, and each system has its own protocols.
- Event authentication: When an event arrives from the external system, you must authenticate it to ensure a malicious caller did not send it. There is no standard for securing webhook events, and you need to understand the specifics of the protocol for each external app you want to integrate with.
- Custom handshakes: External systems often impose custom protocols on the webhook implementers to ensure the webhook implementation is healthy and secure. You need to understand those protocols and properly respond to them to avoid quietly invalidating or removing your registration.
- Identity mapping: The problem is similar to the identity mapping in an outgoing integration but in reverse. The event you receive typically contains a hint of the identity of the tenant in the external system. Before you can perform a meaningful action within your application, you need to identify the tenant in your application the tenant from the external system maps to.
- Throttling: Unlike in the case of an outgoing integration, this is about protecting your own systems against an inordinate amount of events or any spikes in traffic. You usually want to ensure the number of concurrent requests to your system does not exceed a particular threshold which your app can safely handle. You can rarely rely on a robust implementation or a dependable retry policy of the external system and so often need to resolve to use queues to smooth out traffic within your app.
- Webhook health: For a variety of reasons, the external system may choose to invalidate or remove your webhook registration. For example, this could happen if your system was down for several hours, a large number of attempted notifications did not make it, and the external system concluded your application was permanently down. When it happens, you will simply stop receiving notifications and will not know whether it is for lack of events or whether your registration is no longer valid. To prevent this, you need to implement proactive checks for the validity of your webhook registration.
Scheduled integrations perform an integration logic by calling out to your customer’s application and external system on a schedule, as opposed to being triggered by an event from one of the systems. For example, you may want to reconcile the status of orders in your application and the Salesforce instance of your customer, for every of your customers, at the same time each night. Or move operational logs from your application to Splunk.
A good way of thinking about this integration pattern is to combine two outgoing integrations, with your own application being one of the external systems. The set of technical challenges are generally similar to the outgoing integration pattern, with more emphasis on the throttling:
- Authentication and authorization: You need to address all the same challenges regarding authentication and authorization to the external system as in the outgoing integration scenario. However, you have more flexibility in operating on your application’s data on behalf of all your users.
- Identity mapping: Like in the outgoing integration scenario, you need to understand the mapping between your tenants and the account and credentials to use in the external system.
- Throttling and retries: This is an interesting problem since in a scheduled integration, you want to perform a very large number of calls to both the external system and your application all at once. To not exceed the throttling limits of the external system and protect your own application against the surge, you need to consider a mechanism to “smooth out” the spike of work. This is often accomplished using queues with defined concurrency levels.