Zoho, Freshworks & SaaS Unicorns Interview Guide
1. Zero to One: Memory Scaling and Lock Granularity
Before answering distributed webhooks and C memory layout questions, you must establish the core mental models.
Pointer Arithmetic Scaling (The 1D Array Mental Model)
In C, pointer arithmetic does not add raw bytes; it adds elements. Think of RAM as a giant 1D array of bytes.
The universal rule: ptr + 1 mathematically translates to address + (1 * sizeof(type)).
- If
char* p = 1000, thenp + 1is1001(becausesizeof(char)is 1). - If
int* p = 1000, thenp + 1is1004(becausesizeof(int)is 4). - If
int (*p)[5] = 1000(pointer to an array of 5 ints), thenp + 1is1020(because5 * 4 = 20bytes).
Lock Granularity (Avoiding the Global Lock)
In LLD (Low-Level Design) rounds, using synchronized on a whole method is an anti-pattern because it serializes execution (only one thread can use the manager at a time).
Instead, use fine-grained locking (like ConcurrentHashMap) so Thread A can book Taxi 1 while Thread B books Taxi 2 simultaneously.
Idempotent API Design
When Webhooks fail to receive a 200 OK, they retry. If a webhook to "Charge $50" retries, you might charge the user twice.
An API is Idempotent if calling it 10 times has the same effect as calling it once. Always include an Idempotency-Key in the request header. The server checks if it has seen the key; if yes, it returns the cached response instead of reprocessing.
1. Metadata and Introduction
- Category: Placements / Enterprise Company Intelligence
- Subcategory: Indian SaaS Unicorns & Bootstrapped Tech Giants
- Difficulty: Advanced (Software Developer / Member of Technical Staff Level)
- Estimated Reading Time: 60 minutes
- Prerequisites: Systems programming in C/C++, Java Concurrency, Object-Oriented Design (LLD), Multi-Tenant System Design, Distributed Systems.
- Learning Outcomes:
- Master the C-level memory model, pointer arithmetic, and stack/heap allocation (Zoho Round 1).
- Solve and mathematically prove complexities for matrix manipulations and string algorithms (Zoho Round 2/3).
- Architect Low-Level Designs (LLD) with complete state-machine tracking and UML representations (Zoho Round 4).
- Design multi-tenant distributed architectures for B2B SaaS (Freshworks).
- Understand high-concurrency protocols, WebSocket streaming, and API gateways (BrowserStack, Postman).
This exhaustive chapter dissects the engineering culture and interview pipelines of prime Indian SaaS unicorns, building up from bitwise memory models to global distributed systems.
2. Zoho Engineering: The Bootstrapped First-Principles Culture
Zoho ignores resumes and degrees, focusing intensely on bare-metal understanding. Their interview pipeline rigorously tests C/C++ memory mechanics before moving to system design.
2.1 The C Memory Model and Execution Traces
When Zoho tests C, they aren't testing syntax; they are testing your mental model of RAM.
Memory Layout of a C Program
A standard C process memory space is divided into:
- Text Segment: Compiled machine code. Read-only.
- Data Segment: Initialized global and static variables.
- BSS Segment: Uninitialized global and static variables (zero-initialized by OS).
- Heap: Dynamically allocated memory (
malloc,calloc). Grows upwards. - Stack: Local variables, function parameters, return addresses. Grows downwards.
Zoho Classic: Complex Pointer Output Prediction
Consider this snippet often seen in Round 1:
#include <stdio.h>
void pointer_trick() {
int arr[] = {10, 20, 30, 40, 50};
int *ptr = arr;
printf("%d\n", *(ptr++));
printf("%d\n", *(++ptr));
printf("%d\n", *ptr + 1);
int *ptr2 = (int*)(&arr + 1);
printf("%d\n", *(ptr2 - 1));
}
Execution Trace & Memory Model Analysis:
arrdecays to a pointer to its first element (e.g., Address0x1000). Elements are 4 bytes each.*(ptr++): The post-increment operator evaluates the pointer, dereferences it (yielding10), and then increments the pointer to0x1004.*(++ptr): The pre-increment operator increments the pointer to0x1008(pointing to30) and then dereferences it. Output:30.*ptr + 1: Dereferences the current pointer (value30) and adds1. Output:31.&arr: This is a pointer to an array of 5 integers, not just an integer pointer.&arr + 1: Addssizeof(int[5])(20 bytes) to the base address. Points to0x1014, just past the end of the array.(int*)(&arr + 1): Casts the array pointer back to an integer pointer.*(ptr2 - 1): Subtracts oneintsize (4 bytes) from0x1014, giving0x1010(the address of50). Dereferencing yields50.
Complexity: Time, Space. Memory offset arithmetic executes in constant CPU cycles.
2.2 Advanced Problem Solving: Matrices and Pattern Printing (Rounds 2 & 3)
Zoho heavily favors matrix manipulation without using extra space, enforcing in-place mutations.
Matrix Spiral Traversal (In-Place)
Problem: Print a given matrix in spiral order.
C++ Implementation:
#include <iostream>
#include <vector>
void printSpiral(const std::vector<std::vector<int>>& matrix) {
if (matrix.empty()) return;
int top = 0;
int bottom = matrix.size() - 1;
int left = 0;
int right = matrix[0].size() - 1;
while (top <= bottom && left <= right) {
// Print top row
for (int i = left; i <= right; ++i)
std::cout << matrix[top][i] << " ";
top++;
// Print right column
for (int i = top; i <= bottom; ++i)
std::cout << matrix[i][right] << " ";
right--;
// Print bottom row
if (top <= bottom) {
for (int i = right; i >= left; --i)
std::cout << matrix[bottom][i] << " ";
bottom--;
}
// Print left column
if (left <= right) {
for (int i = bottom; i >= top; --i)
std::cout << matrix[i][left] << " ";
left++;
}
}
}
Complexity Proof:
- Time Complexity: . Every element is visited exactly once. We use 4 pointers constraining the unvisited inner matrix. The sum of lengths of the 4 loops per outer iteration exactly matches the perimeter of the unvisited region.
- Space Complexity: auxiliary space. We merely keep track of 4 scalar integer pointers (
top,bottom,left,right).
Edge Cases:
- Single row matrix (). The
top <= bottomcondition handles preventing duplicate reversed printing. - Single column matrix (). The
left <= rightcondition prevents duplicate vertical printing. - Empty matrix.
The Look-and-Say Sequence
Problem: Generate the -th term of the sequence: 1, 11, 21, 1211, 111221, 312211...
Java Implementation with String Builder:
public class ZohoLookAndSay {
public static String getNextTerm(String s) {
StringBuilder result = new StringBuilder();
int count = 1;
for (int i = 0; i < s.length(); i++) {
if (i + 1 < s.length() && s.charAt(i) == s.charAt(i + 1)) {
count++;
} else {
result.append(count).append(s.charAt(i));
count = 1;
}
}
return result.toString();
}
public static String generateNthTerm(int n) {
if (n <= 0) return "";
String term = "1";
for (int i = 1; i < n; i++) {
term = getNextTerm(term);
}
return term;
}
}
Complexity Proof:
- Let be the length of the -th sequence. John Conway proved that the length of the sequence grows at a constant rate (Conway's constant).
- Therefore, .
- Time Complexity: , exponential, because we must generate all intermediate strings up to .
- Space Complexity: to store the final and intermediate strings.
3. Low-Level Design (LLD) - The Zoho Round 4 Benchmark
Zoho requires candidates to build robust, modular, and thread-safe min-applications in a 2-hour window.
3.1 Call Taxi Booking System
Requirements:
- 6 stations (A, B, C, D, E, F) situated 15 km apart linearly.
- Multiple taxis. A taxi charges Rs.100 for the first 5 km and Rs.10 for each subsequent km.
- When a user books a taxi, the system should allocate the nearest free taxi. If multiple are at the same distance, allocate the one with the minimum total earnings.
System Architecture and Entity Design
classDiagram
class Taxi {
-int id
-char currentStation
-int totalEarnings
-int freeTime
+bookTaxi(request)
+calculateEarnings(distance)
+isFree(time)
}
class Booking {
-int bookingId
-int customerId
-char pickupPoint
-char dropPoint
-int pickupTime
-int dropTime
-int amount
}
class SystemManager {
-List~Taxi~ taxis
+handleRequest(customerId, pickupPoint, dropPoint, pickupTime)
+findBestTaxi(pickupPoint, pickupTime)
}
Taxi "1" -- "*" Booking : manages
SystemManager "1" -- "*" Taxi : allocates
Multi-threaded Java Implementation snippet
import java.util.*;
class Taxi {
int id;
char currentStation;
int totalEarnings;
int freeTime;
List<String> bookingHistory;
public Taxi(int id) {
this.id = id;
this.currentStation = 'A'; // Initial station
this.totalEarnings = 0;
this.freeTime = 6; // Start time at 6 AM
this.bookingHistory = new ArrayList<>();
}
// Thread-safe update
public synchronized void completeBooking(char dropStation, int travelTime, int amount) {
this.currentStation = dropStation;
this.freeTime += travelTime;
this.totalEarnings += amount;
}
}
class TaxiManager {
List<Taxi> taxis;
public TaxiManager(int numTaxis) {
taxis = new ArrayList<>();
for (int i = 1; i <= numTaxis; i++) {
taxis.add(new Taxi(i));
}
}
public synchronized Taxi assignTaxi(char pickup, int time) {
Taxi bestTaxi = null;
int minDistance = Integer.MAX_VALUE;
int minEarnings = Integer.MAX_VALUE;
for (Taxi t : taxis) {
if (t.freeTime <= time) { // Taxi is free
int dist = Math.abs(t.currentStation - pickup);
if (dist < minDistance) {
minDistance = dist;
bestTaxi = t;
minEarnings = t.totalEarnings;
} else if (dist == minDistance) {
if (t.totalEarnings < minEarnings) {
bestTaxi = t;
minEarnings = t.totalEarnings;
}
}
}
}
return bestTaxi;
}
}
Design Patterns Used:
- Mutex / Monitor Lock (
synchronized): Ensures that concurrent booking requests do not result in race conditions where multiple users are assigned the same taxi. - Factory Pattern (Implicit): Taxi creation and management are encapsulated within
TaxiManager.
4. Freshworks & SaaS Architecture (High-Level Design)
SaaS unicorns like Freshworks solve complex problems in Multi-Tenancy. A tenant is a distinct customer (organization) using the software.
4.1 Multi-Tenant Data Models
There are three primary models for storing tenant data:
- The Silo Model (Isolated): Each tenant gets a separate database instance.
- Pros: Maximum security, easy compliance (HIPAA, GDPR). No noisy neighbors.
- Cons: Extremely expensive, hard to manage migrations across thousands of DBs.
- The Bridge Model (Schema-per-Tenant): Tenants share a DB engine but have separate schemas/tables.
- Pros: Better resource utilization than Silo, moderate isolation.
- Cons: Schema updates are still painful. Postgre's maximum schema limit can be reached.
- The Pool Model (Shared Database, Shared Schema): All tenants share tables. A
tenant_idcolumn acts as the discriminator.- Pros: Highly scalable, single migration path, lowest cost.
- Cons: Risk of cross-tenant data leaks. Requires strict Row-Level Security (RLS).
Implementing Row Level Security (RLS) in PostgreSQL
Freshworks relies on PostgreSQL RLS to enforce isolation in the Pool Model.
-- Enable RLS on the table
ALTER TABLE tickets ENABLE ROW LEVEL SECURITY;
-- Create a policy to restrict rows by tenant_id
CREATE POLICY tenant_isolation_policy ON tickets
USING (tenant_id = current_setting('app.current_tenant_id')::UUID);
When a request arrives, the API gateway determines the tenant from the JWT or API key and sets the session variable. The application layer cannot accidentally query another tenant's data, enforcing a strict zero-trust data model.
4.2 Background Processing and Webhooks
SaaS applications depend heavily on asynchronous processing.
- Message Brokers: RabbitMQ, Kafka.
- Workers: Sidekiq (Ruby), Celery (Python).
Webhook Delivery Guarantee: If a SaaS promises 99.99% webhook delivery, they must handle downstream failures.
- Exponential Backoff: Retrying with increasing delays.
- Circuit Breaker Pattern: If the client's endpoint fails consecutively, open the circuit and stop sending traffic to prevent cascading failures.
5. BrowserStack & Postman: High Concurrency Engineering
BrowserStack and Postman focus on high network concurrency, virtualization, and protocol efficiency.
5.1 BrowserStack: WebSocket Streaming and Virtualization
BrowserStack streams headless browser instances to the client's UI in real-time. This requires bypassing HTTP overhead.
- WebSockets: Provide full-duplex communication over a single TCP connection.
- Canvas Streaming: Transmitting diffs (deltas) of the virtual DOM or the actual framebuffer to minimize latency.
Execution Trace of WebSocket Handshake:
- Client sends HTTP GET with
Upgrade: websocketheader. - Server responds with HTTP 101 Switching Protocols.
- Connection is kept open; data is framed and sent bidirectionally.
5.2 Postman: API Schema Validation and Proxying
Postman evaluates complex JSON payloads against OpenAPI or JSON Schema formats.
AST (Abstract Syntax Tree) for Validation: Validating gigabytes of API payloads requires parsing JSON efficiently. High-performance JSON parsers (like SIMDjson) use Single Instruction Multiple Data (SIMD) CPU instructions to validate characters in parallel, achieving validation at gigabytes per second.
6. Comprehensive Interview Questions & Edge Cases
[!IMPORTANT] Treat these questions as a litmus test for your understanding of the core concepts presented in this chapter.
Q1. (Zoho Round 1) Analyze the following C struct memory layout.
struct SystemFlag {
char a;
int b;
char c;
};
Answer: Due to memory alignment requirements, a takes 1 byte, followed by 3 bytes of padding. b takes 4 bytes. c takes 1 byte, followed by 3 bytes of padding. Total size is 12 bytes. If ordered as char a; char c; int b;, the size becomes 8 bytes, saving memory.
Q2. (Freshworks) How do you prevent the "Noisy Neighbor" problem in a shared DB SaaS architecture? Answer: By implementing Rate Limiting at the API Gateway using Redis-backed Token Buckets, and allocating resource quotas per tenant. At the database level, Query timeouts and Connection Pooling (PgBouncer) ensure no single tenant monopolizes DB connections.
Q3. (BrowserStack) How would you design a load balancer for persistent WebSocket connections? Answer: Standard Round-Robin fails because WS connections are long-lived. You must use Least-Connections algorithms and ensure consistent hashing so that reconnections route to the same instance (Session Stickiness), or better, decouple connection state using a distributed pub/sub like Redis PubSub so any node can handle the socket.
Q4. (Zoho Round 3) Prove that validating a Sudoku board requires space if the board size is fixed at . Answer: Because the board size is invariant (always ), any array or bitmask used to track seen digits is capped at size 9. simplifies to auxiliary space. The time complexity is .
Q5. (Postman) How does HTTP/2 improve upon HTTP/1.1 for fetching massive API ecosystems? Answer: HTTP/2 introduces Multiplexing, allowing multiple requests and responses to interleave on a single TCP connection, eliminating Head-of-Line blocking at the network layer. It also uses HPACK for header compression.
7. Summary & Conclusion
Cracking Zoho, Freshworks, BrowserStack, and Postman requires bridging the gap between hardware-level mechanics and cloud-scale abstractions.
- Zoho demands perfection in space complexity, bare-metal C programming, and flawless multi-threading object-oriented designs.
- Freshworks demands expertise in tenant isolation, SaaS pricing architectures, and resilient asynchronous webhooks.
- BrowserStack and Postman demand mastery over network protocols, WebSockets, high-concurrency systems, and high-performance serialization.
By approaching these engineering challenges from first principles—analyzing the memory model, mathematically proving time/space complexity, and designing robust system architectures—you solidify your path to a Top-Tier Indian SaaS engineering role.
Projects
- Multi-Tenant Helpdesk System
- Step 1: Build a robust backend API using Node.js or Spring Boot connected to a PostgreSQL database. Implement a shared-database, shared-schema (Pool Model) multi-tenancy architecture where a dedicated
tenant_idcolumn explicitly separates organizational data. - Step 2: Integrate comprehensive Role-Based Access Control (RBAC) ensuring that users from one tenant organization absolutely cannot access or modify another tenant's data. Apply Row-Level Security (RLS) policies natively in PostgreSQL for bulletproof isolation.
- Step 3: Implement distributed caching using Redis to drastically reduce database hits for frequently accessed tenant configurations and API rate limiting quotas.
- Deliverable: A highly scalable helpdesk backend akin to Freshdesk, complete with API rate limiting, webhook dispatchers, and completely isolated tenant environments.
- Step 1: Build a robust backend API using Node.js or Spring Boot connected to a PostgreSQL database. Implement a shared-database, shared-schema (Pool Model) multi-tenancy architecture where a dedicated
- Real-time Log Streaming Service
- Step 1: Create an asynchronous WebSocket server in C++ or Go capable of simultaneously handling tens of thousands of persistent concurrent connections with minimal overhead.
- Step 2: Utilize a high-throughput message broker like Apache Kafka to ingest system logs from various microservices, routing them efficiently to explicitly subscribed WebSocket client dashboards.
- Step 3: Optimize internal memory consumption by strictly utilizing advanced circular buffers, ensuring that the C/C++ memory model is respected and raw pointer operations are executed efficiently without causing any memory leaks or segmentation faults.
- Deliverable: A BrowserStack-style real-time streaming dashboard for observing container logs and application states globally.
Assignments
- Memory Allocation Tracer
- Deliverables: Write a custom, low-level C program that actively intercepts standard
mallocandfreesystem calls using theLD_PRELOADenvironment variable technique. Log the precise allocation sizes, memory pointer addresses, and high-resolution timestamps to a dedicated log file. Thoroughly analyze the generated logs to detect insidious memory leaks and dangling pointers within a provided deliberately buggy application. This assignment extensively trains your mental model of heap memory mechanics, which is heavily tested at Zoho.
- Deliverables: Write a custom, low-level C program that actively intercepts standard
- In-Place Matrix Transformations
- Deliverables: Solve exactly five advanced matrix manipulation problems (such as rotating a matrix by 90 degrees strictly in-place, finding the maximum sub-square matrix composed entirely of 1s, and complex matrix spiral generation) using strictly auxiliary space overhead. Provide rigorous mathematical proofs for both time and space complexities written as comprehensive documentation comments directly within your C++ or Java source code.
- Webhook Retry Mechanism
- Deliverables: Implement an industrial-grade exponential backoff algorithm in Python, Java, or Go. Create a robust mock SaaS webhook dispatcher that resiliently handles 503 (Service Unavailable) and 429 (Too Many Requests) HTTP status codes from a destination server endpoint. The system must intelligently pause execution, increase the wait time exponentially between consecutive retries, and finally route the unsendable payload into a reliable Dead Letter Queue (DLQ) after precisely five failed delivery attempts.
Debugging Guide
When building multi-tenant SaaS applications or highly optimized low-level C programs, the debugging process can become incredibly complex and frustrating. Here are some of the most common critical bugs and their corresponding professional fixes:
- Common Bug: Segmentation Faults and Memory Corruption in C/C++
- Symptoms: The program crashes abruptly, often with a cryptic core dump, or behaves non-deterministically due to corrupted memory segments.
- Fixes: Actively use debuggers like
gdbor memory analysis tools likevalgrindto trace the exact line of execution causing the catastrophic crash. Strictly ensure that all pointers are properly initialized toNULLor a valid address before dereferencing. Meticulously check for off-by-one algorithmic errors in array boundary iterations. Never return the memory addresses of local function variables, as they reside dynamically on the stack memory and are instantly destroyed upon the function's return.
- Common Bug: Insidious Cross-Tenant Data Leakage
- Symptoms: A user securely authenticated into Tenant A mysteriously sees database records exclusively belonging to Tenant B.
- Fixes: Rigorously verify that the central API middleware layer correctly extracts the specific
tenant_idfrom the secure JWT payload and accurately appends it to every single underlying database query. Critically, rely strictly on Database Row-Level Security (RLS) constraints rather than fragile application-level conditional filtering to mathematically guarantee absolute multi-tenant data boundaries.
- Common Bug: Premature WebSocket Connection Drops
- Symptoms: Active clients frequently disconnect inexplicably from real-time streaming dashboards.
- Fixes: Immediately implement proactive heartbeat mechanisms utilizing standard Ping/Pong WebSocket frames to keep the TCP connections reliably alive through intermediate load balancers and proxy servers.
Testing Strategy
A meticulously designed testing strategy is absolutely crucial for verifying high-concurrency cloud systems and bare-metal performance-critical applications.
- Unit Testing Memory Constructs: In C and C++ environments, utilize robust frameworks like Google Test. Actively mock all external network and filesystem dependencies to isolate and verify core pointer logic. Crucially, execute all test suites dynamically via
valgrindwithin your automated CI/CD pipelines to mathematically ensure zero memory leaks. Configure the build pipeline to explicitly fail if the memory leak count is anything greater than absolute zero. - Integration Testing for Multi-Tenancy Systems: Automated integration tests must systematically verify tenant data isolation mechanisms. Programmatically create distinct test tenants and insert corresponding mocked database records. Write aggressive test assertions that maliciously attempt to query Tenant B's sensitive data using Tenant A's restricted authorization tokens. These critical integration tests must definitively assert HTTP 403 Forbidden responses or perfectly empty datasets to validate underlying PostgreSQL Row-Level Security (RLS) configurations.
- Load, Stress, and Concurrency Testing: Performance simulation tools like Apache JMeter, Gatling, or Grafana k6 are practically essential. Artificially simulate tens of thousands of concurrent virtual users initiating simultaneous WebSocket handshakes or aggressively creating massive API JSON payloads. Continuously monitor CPU utilization, Heap Memory limits, and Garbage Collection pause metrics. Precisely identify at exactly what concurrency threshold the application latency significantly degrades or the API gateway forcibly begins to throttle incoming requests.
FAQs
- Q: Are professional certifications strictly necessary for securing roles at Zoho or Freshworks?
- A: Absolutely not. Both Zoho and Freshworks strongly prioritize raw foundational engineering skills over any commercial certifications. They care infinitely more about your tangible ability to build a robust system entirely from scratch, seamlessly handle raw memory pointers without crashing, and design intelligently scalable software architectures. Focus intensely on building comprehensive personal projects rather than merely accumulating theoretical certificates.
- Q: What programming languages are considered best for successfully passing these specific technical interviews?
- A: For Zoho specifically, C, C++, and Java are heavily preferred by interviewers due to their intensive emphasis on manual memory management, system-level execution traces, and rigid object-oriented design patterns. For Freshworks and BrowserStack, the specific programming language matters far less than the underlying system architecture; however, modern languages like Java, Go, Python, and Node.js are extremely widely used, universally accepted, and highly recommended.
- Q: Exactly how deep do I mathematically need to understand multi-tenancy architectures?
- A: If you are interviewing as a fresher, fundamentally understanding the basic structural models (Silo, Bridge, Pool) and the core concept of organizational data isolation is generally sufficient. For an experienced senior hire, you must intimately know how to actually implement PostgreSQL Row-Level Security, configure API rate limiting algorithms per specific tenant, and shard relational databases efficiently to systematically handle the dreaded noisy neighbor performance problem.
Revision Notes / Cheat Sheet
This quick revision cheat sheet encapsulates the core engineering concepts heavily evaluated across top-tier Indian SaaS technical interviews. Review these foundational principles thoroughly before your final technical rounds.
| Core Engineering Concept | Key Technical Principles & Interview Focus | Target SaaS Company | |--------------------------|--------------------------------------------|---------------------| | The C Memory Layout | Deep understanding of Stack, Heap, BSS, Data, and Text segments. Complex pointer arithmetic evaluation depends explicitly on specific data types and sizes. | Zoho | | In-Place Algorithms | Avoid utilizing extra arrays or hash maps. Master utilizing multiple pointers or bitwise manipulation techniques to consistently achieve mathematical space complexity. | Zoho | | Object-Oriented LLD | Strict Data Encapsulation, explicit Mutex/Monitor locks ensuring thread safety, and Factory design patterns for efficient entity instantiation and system management. | Zoho | | Multi-Tenancy Architecture | Comprehensive knowledge of Silo, Bridge, and Pool models. Mastery of Database Row-Level Security (RLS) to algorithmically prevent catastrophic cross-tenant data leaks. | Freshworks | | High-Concurrency WebSockets | Implementing Full-duplex, long-lived persistent TCP connections. Explicitly requires mandatory Ping/Pong heartbeat frames for continuous keep-alive through load balancers. | BrowserStack | | High-Speed API Parsing | Constructing Abstract Syntax Trees (AST) and utilizing SIMD CPU instructions to achieve ultra-high-throughput JSON schema validation at gigabytes per second. | Postman | | Asynchronous Message Brokers | Decoupling complex microservices using Apache Kafka or RabbitMQ. Implementing rigorous Dead Letter Queues (DLQ) and exponential backoffs for robust webhooks. | Freshworks, General SaaS |