Hello! Welcome to the first lesson in our course on designing a large-scale log ingestion system.
In any system design process, the most critical first step is to thoroughly understand and define the requirements. Jumping into architectural diagrams without a clear set of goals can lead to a system that doesn't meet user needs, can't scale, or has critical security flaws.
This lesson is dedicated to building that solid foundation. We will define the functional requirements (what the system must do) and the non-functional requirements (the qualities it must possess, such as performance and reliability). Specifically, by the end of this lesson, you will be able to define the API contract, data format, and availability Service Level Agreements (SLAs) for the webhook-based log ingestion system you're building. We'll use your project's specific context—ingesting logs from a third-party provider like Okta—to make this as practical as possible.
Let's begin.
1. The Art of Asking the Right Questions
Before defining requirements, a good engineer collaborates with stakeholders to clarify the problem. The assumptions we make at the start will drastically shape the final design.
To get into this mindset, I'd like you to watch a segment of the following video. It outlines several key questions to ask when designing a webhook system. As you watch, think about how these questions apply to your goal of ingesting logs from Okta.
Design Webhook - Most Frequently Asked Question in OpenAI in 2025
This video from ShowOffer provides a great framework for clarifying requirements before diving into design. Focus on the types of questions the presenter suggests asking.
Watch from 02:01 to 06:02. Pay close attention to the questions about event types, volume, delivery guarantees, ordering, latency, and security.
The video raises several excellent points. For our project, we can frame the answers like this:
- What types of events? Okta event logs, which are often related to security and user activity (e.g.,
user.session.start). These are critical for auditing and security monitoring, so reliability will be a high priority. - What is the expected volume? This is something we'll need to estimate, but providers like Okta can generate a very high volume of events, especially in a large organization. We must design for scale.
- What delivery guarantees are required? We need to know if we should expect events "at least once," "at most once," or "exactly once." This dictates how we handle duplicates.
- Is event ordering important? For log analysis, chronological order is often crucial. We need to know if the provider guarantees order or if we must handle out-of-order events.
- What are the latency and security requirements? The provider will likely have a timeout for webhook calls, and we must handle authentication to ensure the requests are legitimate.
Answering these questions moves us from a vague problem statement to a set of concrete constraints we can design against.
2. Defining Functional Requirements
Functional requirements describe the specific behaviors and features the system must support. For our log ingestion pipeline, the core functionality is centered on receiving and processing the incoming data.
To explore this, let's watch another segment from the same video, which transitions from clarifying questions to defining concrete requirements.
Design Webhook - Most Frequently Asked Question in OpenAI in 2025
The next part of the 'Design Webhook' video explicitly lists common functional and non-functional requirements. This will give us a strong template to adapt for our system.
Watch from 06:02 to 08:31. Focus on the definitions of functional requirements like 'register a webhook' and 'receive events'.
The video discusses building a webhook provider system, which includes APIs for clients to register their webhooks. In our case, we are the webhook consumer. Okta is the provider. This means we won't be building a registration API for Okta to call. Instead, our functional requirements are focused on the receiving end:
- Unified Log Ingestion: The system must expose a secure HTTPS endpoint to receive log events from external providers (initially Okta) via HTTP POST requests. This aligns with the "unified log collection" goal for any logging system.
- Authentication: The system must authenticate every incoming request to verify it originates from a trusted source (Okta) and not a malicious actor.
- Validation: The system must perform basic validation on the incoming payload to ensure it conforms to the expected structure.
- Acknowledgement: The system must promptly send a success acknowledgement (e.g., an HTTP
2xxstatus) to the provider to confirm receipt. This is critical for preventing the provider from resending the same event unnecessarily. - Durable Storage: The system must durably persist the validated log event for further processing. "Durable" means the data survives machine failure.
This list defines what our system needs to do. Next, we'll define how well it needs to do it.
3. Defining Non-Functional Requirements (NFRs) & SLAs
Non-Functional Requirements (NFRs), or quality attributes, are just as important as functional ones. They define the system's operational characteristics and form the basis of our Service Level Agreements (SLAs). For a backend system like this, NFRs are paramount.
Let's look at a video that discusses NFRs in the context of a distributed logging system. It provides some concrete numbers which are useful for context.
Distributed Logging System Design with Ex-Amazon SDE
This video from Sweet Codey discusses the NFRs for a logging system, providing specific targets for latency, scalability, and availability.
Watch from 07:37 to 11:07. Note the emphasis on low latency, high scalability, availability, and security, including the sample metrics provided.
Combining these general principles with the specific documentation from our provider, Okta, allows us to define precise NFRs.
The official Okta Event Hooks documentation is our source of truth. It contains specific details on timeouts, retry logic, and security that directly shape our NFRs.
Read the sections 'Requests sent by Okta', 'Timeout and retry', 'HTTP Headers', 'Security', and 'Your service's responses...'. These sections are the most critical for defining our system's contract with Okta.
Based on these resources, we can establish the following NFRs for our system:
- Availability (SLA): The ingestion endpoint must be highly available. A common target for such critical infrastructure is 99.9% to 99.99% uptime. If our endpoint is down, we lose logs, which could be a major security incident.
- Latency: The endpoint must respond to Okta within 3 seconds. The Okta documentation explicitly states this is their timeout. A slow response will be treated as a failure, causing retries and potential data duplication. This single constraint strongly suggests an asynchronous processing architecture, where we acknowledge the request immediately and process the data later.
- Reliability & Data Durability:
- No Data Loss: The system must be designed to prevent log loss. Once we send a
2xxresponse, the event must be durably stored. - At-Least-Once Delivery: Okta guarantees "at-least-once" delivery. This means our system must be idempotent—processing the same event multiple times should have the same result as processing it once. We will design for this in a later lesson.
- No Data Loss: The system must be designed to prevent log loss. Once we send a
- Scalability: The system must scale horizontally to handle high-throughput bursts of logs without affecting performance. While Okta has a daily rate limit, our architecture should not be the bottleneck.
- Security:
- The endpoint must be exposed over HTTPS (TLS).
- It must validate a shared secret passed in the
Authorizationheader of every request from Okta. This prevents unauthorized clients from pushing fake logs to our system.
4. Defining the API Contract and Data Format
Now let's synthesize this information into a formal API contract. This contract specifies exactly what our endpoint expects and how it will respond.
API Contract: Ingesting Okta Event Logs
| Aspect | Specification |
|---|---|
| Endpoint | [Your Service URL] (e.g., https://logs.yourcompany.com/ingest/okta) |
| HTTP Method | POST |
| Request Headers |
|
| Request Body | A JSON payload containing an array of log events. |
| Success Response |
|
| Error Response |
|
| Response Latency | The success response must be sent within 3 seconds. |
This contract is our guide for implementation. The 3-second latency requirement is a strong driver for the design shown in this sequence diagram:

Data Format
The data we receive will be in a JSON format defined by Okta. Understanding this schema is crucial for parsing and storing the logs correctly.
The Okta documentation provides a sample payload. The key elements are:
- A root object containing metadata about the hook itself.
- A
data.eventsfield, which is an array of one or more log events. This means our service must be prepared to handle batches of events in a single POST request. - Each event in the array has a rich structure, including:
eventId: A unique ID for the event, which will be critical for implementing idempotency.eventType: e.g.,user.session.start. Useful for filtering and routing.published: The timestamp of the event.actor,client,target: Rich objects describing who did what, from where, and to what.
For now, the key takeaway is that we are receiving structured JSON. Internally, for efficiency, you might consider serializing this data into a more compact binary format like Protocol Buffers (Protobuf) before sending it to a message queue, but the public contract is JSON.
Test your understanding!
Based on the Okta documentation and the NFRs we've defined, what is the single most important constraint that forces an asynchronous architecture for your ingestion service, and why?
Show answer
The 3-second response timeout. To reliably process an incoming log event (validate, persist, etc.) without risking a timeout, the best practice is to do the bare minimum work synchronously and defer the rest. The synchronous work should be: authenticate, validate the payload format, push it to a durable message queue, and return a 200 OK. The actual processing and storage in a database can then be handled asynchronously by a consumer.
Conclusion
In this lesson, we established the foundational requirements for our log ingestion system. This is the blueprint that will guide all our subsequent design decisions.
Key Takeaways:
- System requirements are paramount: We distinguished between functional requirements (what the system does) and non-functional requirements (its quality attributes).
- The provider dictates the contract: Our system must conform to the API contract defined by Okta, including the endpoint behavior, security model (
Authorizationheader), and data format (JSON). - NFRs drive architecture: A single non-functional requirement—the 3-second response timeout—strongly pushes us toward an asynchronous design using a message queue to decouple ingestion from processing.
- Reliability is key: Okta promises "at-least-once" delivery, which means our system must be designed for idempotency to handle duplicate events without causing data corruption.
With this clear set of requirements, we are now ready to start thinking about the scale of the system.
Preview of the Next Lesson: In the next lesson, we will move on to capacity planning. We will learn how to perform back-of-the-envelope calculations to estimate the required write throughput and storage needs based on expected log volume. This will help us choose the right technologies and provision adequate resources for our system.