API Reliability Intermediate

How to Spike a Third-Party Realtime API Before You Commit to Build

Test latency, clock ownership, reconnection, delivery semantics, and rate limits to produce an evidence-based go/no-go assessment.

2–5 days Intermediate Octacer Engineering July 21, 2026
An engineer stress-testing a live realtime connection, deliberately severing it to watch it recover.

Overview

When a feature depends on a third-party realtime API, the estimate is only as good as your assumptions about that API's behavior. Latency, message ordering, clock ownership, and reconnection semantics are unknowable until you have hit the real endpoint with real traffic patterns. A short technical spike — two to five focused days of investigation — answers those questions with evidence, so the build estimate rests on measured behavior rather than vendor documentation and guesswork.

By the end of this guide, you will have: a reproducible spike plan that produces a written reliability assessment for any third-party realtime API, including measured latency figures, connection behavior under failure, message-ordering and clock-semantics findings, and a clear go/no-go recommendation for the build phase.

The spike produces four deliverables:

  1. Latency profile — round-trip, first-message, and sustained-throughput figures under realistic network conditions.
  2. Clock-ownership analysis — whether timestamps are server-authoritative or client-generated, and what that means for your data model.
  3. Reconnection behavior — what happens when connections drop, and whether client-side recovery logic is required.
  4. Recommendation — a written go/no-go assessment with evidence for each claim.

Prerequisites

Before starting the spike, confirm the following are available.

Tools

A runtime environment for your spike client. Node.js with ws or socket.io-client, Python with websockets, or any language with a WebSocket or SSE client library will work. The choice should match your production stack so measured behavior carries over.
A tool for measuring wall-clock time with millisecond precision — the runtime's Date.now() or a monotonic timer is sufficient.
A script runner (npm scripts, Makefile, or plain shell) to orchestrate spike runs.
A code repository — the spike itself is throwaway, but the results and the harness that produced them are not.

Access

A sandbox or development account for the third-party API, with credentials that permit non-production traffic.
Access to the API's official documentation, including the protocol specification (WebSocket subprotocol, SSE event names, or pub/sub topic structure), authentication handshake, and reconnection guidance.
If the API enforces rate limits, confirmation of the development-tier limits so the spike does not get throttled mid-run.

Data

A small set of representative messages or events to publish and subscribe to. These should resemble the real payloads your production feature will handle — same shape, similar size, same cardinality of nested fields.
The API base URL and authentication credentials for the sandbox environment.

Knowledge

Basic familiarity with WebSocket or SSE client libraries in your chosen runtime.
Understanding of how to measure elapsed time in your runtime without blocking the event loop.

Steps

The spike follows a deliberate sequence. Each step answers a specific question. Do not skip ahead — the later steps depend on the measurements and tooling established earlier.

Step 1 — Build a minimal connectivity harness

  1. 1

    Build Harness

    Create a small client that connects to the realtime API, authenticates, subscribes to a test channel or topic, and logs every message with a client-side timestamp.

  2. 2

    Measure Latency

    Run the connectivity harness from the network location your production workload will actually use. If your production servers are in us-east-1, run the spike from us-east-1. If your users are geographic, run it from the regions that matter.

  3. 3

    Stress Test

    Production realtime features do not receive one message per minute. They receive bursts. The spike must measure latency under the message rate your production feature will actually handle.

  4. 4

    Check Clocks

    Realtime APIs timestamp their messages. The critical question is: whose clock produced that timestamp?

  5. 5

    Test Recovery

    Production connections drop. The spike must establish what happens when they do.

  6. 6

    Write Report

    The spike is worthless if its findings stay in a log file. Write a report that answers the five questions the build team actually needs answered:

The harness should be deliberately minimal. The point is to measure the API's behavior, not to build part of the production feature.

// spike-client.js — simplified
const WebSocket = require('ws');

const ws = new WebSocket('<API_WS_URL>', {
  headers: { Authorization: `Bearer ${process.env.API_TOKEN}` }
});

const connectTime = Date.now();

ws.on('open', () => {
  console.log('CONNECTED', Date.now() - connectTime);
  ws.send(JSON.stringify({
    type: 'subscribe',
    channel: 'spike-test'
  }));
});

ws.on('message', (data) => {
  const payload = JSON.parse(data.toString());
  console.log(JSON.stringify({
    receivedAt: Date.now(),
    sentAt: payload.sentAt || null,
    serverTime: payload.serverTime || null,
    payload
  }));
});

ws.on('close', (code, reason) => {
  console.log('CLOSED', code, reason.toString());
});

ws.on('error', (err) => {
  console.error('ERROR', err.message);
});

Run the harness for a fixed interval — five minutes is a reasonable starting point — and save the output to a log file.

API_TOKEN="<API_TOKEN>" node spike-client.js > spike-1.log

Expected result: The connection succeeds, authenticated subscription messages arrive, and the log file contains one line per received message with a client-side timestamp.

Step 2 — Measure connection latency across regions

For each region, measure:

  • Time to connect — from client initiation to the server's connection confirmation.
  • Time to first message — from the moment the client publishes a test message to the moment it receives its own message back on the subscribed channel.
  • Round-trip latency — publish a message with a client timestamp, receive it back, and compute receivedAt - sentAt.

Repeat the measurement at least 10 times per region. Realtime APIs are noisy; a single sample is not evidence.

for i in $(seq 1 10); do
  API_TOKEN="<API_TOKEN>" node spike-client.js >> spike-2-region.log
  sleep 5
done

Expected result: A table of measurements per region showing minimum, median, p95, and maximum for connection time and round-trip latency.

Step 3 — Measure sustained latency under a realistic message rate

Estimate the production message rate first. A typical financial-feed integration might receive 10–50 messages per second during active trading. A chat feature might receive 1–5 per second. Use the rate that reflects reality, not the rate the vendor advertises.

Extend the harness to publish test messages at your target rate and measure per-message latency:

// burst-publish.js — simplified
const WebSocket = require('ws');
const ws = new WebSocket('<API_WS_URL>', {
  headers: { Authorization: `Bearer ${process.env.API_TOKEN}` }
});

const RATE_PER_SECOND = 20;
const DURATION_SECONDS = 60;

let sentCount = 0;
let receivedCount = 0;

function sendBatch() {
  const now = Date.now();
  for (let i = 0; i < RATE_PER_SECOND; i++) {
    ws.send(JSON.stringify({
      type: 'publish',
      channel: 'spike-test',
      data: { sentAt: now, seq: sentCount++ }
    }));
  }
}

ws.on('open', () => {
  const interval = setInterval(sendBatch, 1000);
  setTimeout(() => {
    clearInterval(interval);
    setTimeout(() => {
      console.log('SUMMARY', { sentCount, receivedCount });
      ws.close();
    }, 5000);
  }, DURATION_SECONDS * 1000);
});

ws.on('message', (data) => {
  receivedCount++;
  const payload = JSON.parse(data.toString());
  if (payload.sentAt) {
    console.log('LATENCY', Date.now() - payload.sentAt);
  }
});

Run this once. Then run it again with the burst pattern your production workload will have — for example, 100 messages in one second followed by 30 seconds of silence, repeated.

Expected result: A latency distribution under sustained and bursty load. Confirm whether latency degrades as the message rate increases, and whether the API drops or reorders messages under load.

Step 4 — Determine clock ownership

Check every field that appears to be a timestamp and determine whether it was set by the server or by the publishing client.

  1. Publish a message with a deliberately incorrect client timestamp — for example, set sentAt to 24 hours in the past.
  2. Observe how the server echoes or transforms that field.
  3. Compare the server-provided timestamps against your own clock to detect skew.
ws.send(JSON.stringify({
  type: 'publish',
  channel: 'spike-test',
  data: {
    sentAt: Date.now() - 86400000,  // 24 hours in the past
    intentionallyWrong: true
  }
}));

The pattern you observe tells you which clock to trust:

  • If the server overwrites the timestamp, the server is authoritative. Fine for ordering, but confirm the server clock has reasonable skew against real time.
  • If the server preserves the client timestamp, your message ordering is only as good as the clients' clocks. This has direct consequences for any "latest state wins" logic in your data model.
  • If the server provides a separate serverTime field alongside the client timestamp, compare them. The delta between them is your clock-skew measurement.

Expected result: A clear statement of which component owns the timestamp, and a measured clock-skew figure between the server and your client.

Step 5 — Test reconnection behavior

Test the following scenarios, in order:

  1. Graceful server shutdown — if your sandbox allows it, restart the API service and observe the close code and whether the client is expected to reconnect manually.
  2. Network interruption — disconnect the client's network for 10 seconds, then restore it. Observe whether the client library auto-reconnects, whether messages received during the outage are replayed or permanently lost, and whether any messages are duplicated on reconnect.
  3. Idle timeout — leave the connection open with no traffic for the vendor's documented idle timeout, and observe whether the server closes the connection and what close code it sends.
// Reconnection observation — simplified
let messagesBySeq = {};
let duplicateCount = 0;

ws.on('message', (data) => {
  const payload = JSON.parse(data.toString());
  if (payload.seq !== undefined) {
    if (messagesBySeq[payload.seq]) {
      duplicateCount++;
      console.log('DUPLICATE', payload.seq);
    }
    messagesBySeq[payload.seq] = true;
  }
  console.log('STATE', {
    readyState: ws.readyState,
    duplicatesSeen: duplicateCount,
    lastSeq: payload.seq
  });
});

For each scenario, record:

  • The close code and reason.
  • Whether client-side reconnection logic triggered automatically.
  • Whether messages were lost, replayed, or duplicated after reconnect.
  • How long the gap in message delivery lasted.

Expected result: A documented reconnection matrix showing behavior for each failure scenario and the delivery semantics (at-most-once, at-least-once, or exactly-once).

Step 6 — Write the spike report

  1. Latency — what is the realistic p95 latency from your production network location, and does it hold under your production message rate?
  2. Clock semantics — who owns the timestamp, and what does your data model need to do to handle it?
  3. Reconnection — who is responsible for recovering from dropped connections, and what delivery semantics does the API actually provide?
  4. Cost envelope — did the spike reveal any rate-limit or quota behavior that will constrain the production design?
  5. Go/no-go — based on the evidence, should the feature be built against this API, built against a different provider, or built with a fallback path?

Configuration

Several settings materially affect spike results. The right value depends on your workload, not on a universal default.

Message Rate

The sustained and burst message rates in Step 3 must match your production workload. Underestimating the rate produces an optimistic latency profile that will not hold in production. Overestimating it may trip the sandbox rate limit and produce a pessimistic profile.

Burst Pattern

Steady-state rate is not the same as burst behavior. Real workloads arrive in clusters — a batch of trades at market open, a wave of messages when users return from lunch. Run at least one burst test at 5–10 times your average rate for a short interval.

Duration

Five minutes per scenario is a reasonable minimum. Realtime APIs exhibit periodic behavior — garbage collection in the vendor's service, infrastructure maintenance windows, network congestion at specific times of day. Duration should cover at least one period of the workload's natural cycle. If the feature is busiest during market hours, measure during market hours.

Network Location

Run the spike from the network location where production will run. Cloud region matters — a latency measurement from your laptop in a coffee shop has no predictive value for a server in us-east-1.

Estimate from actual business requirements. A chat feature handling 200 concurrent users typically generates 1–5 messages per second. A market-data feed generates 20–100 messages per second during active periods. Use the figure your feature will reasonably encounter.

Verification

The spike is complete when its findings are reproducible and its conclusions are traceable to specific log entries.

Functional Check

Re-run the connectivity harness from Step 1 and confirm the connection still succeeds. The entire spike is invalid if the harness itself is broken.

Data Check

For the latency measurements, confirm that the log contains the expected number of data points. A five-minute run at 20 messages per second should produce roughly 6,000 latency samples. If the log contains dramatically fewer, messages were dropped and that is itself a finding — but it must be recorded as such.

Failure Check

Repeat the network-interruption test from Step 5 and confirm the observed reconnection behavior is consistent. Reconnection behavior that differs between runs indicates nondeterminism in the API, which is a material finding for the build phase.

Repeatability

Run the burst test twice. The median latency should be within the same order of magnitude across runs. If the second run shows latency 10 times higher than the first, the sandbox may be throttling your test traffic — review the rate-limit response headers or error codes.

Log Traceability

Each report conclusion must reference the specific log file and line range that supports it. A report that claims "p95 latency of 400ms" must be able to point to the exact measurement run that produced that figure. If a conclusion cannot be traced to a log entry, it is an assumption, not a spike finding.

Troubleshooting

Drop After Auth

Check that the authentication handshake matches the vendor's spec exactly. Many realtime APIs require the token to be passed as a query parameter, a header, or a field inside the first message — and the correct location varies by vendor. Inspect the server's close code: an authentication-related close code (typically 4001–4009 in the WebSocket range) confirms this.

Identical Latency

This may indicate the messages are being read from a local cache or a static fixture rather than traversing the real network path. Publish messages with unique payloads and verify the echoed payload matches what you sent. If the API echoes the same canned payload each time, you are not measuring real end-to-end latency.

Rate Limit Hit

Check the vendor's development-tier rate limits before designing the burst test. If the limit is lower than your production estimate, that is a material finding — the production design will need to handle throttling or negotiate a higher quota. Adjust the burst test to the highest sustainable rate and record the actual ceiling.

Inconsistent Recovery

Consistent reconnection behavior is a reliability criterion. If the same failure scenario produces different outcomes across runs, the vendor's reconnection semantics are not deterministic. This is a significant finding — client-side recovery logic will need to handle the most conservative case.

Clock Skew

Compare the server-provided timestamps against a trusted time source such as an NTP-synced clock. If the skew is more than a few seconds, ordering based on server timestamps may conflict with ordering based on business events in your own systems. Document the skew figure in the report; it affects how the production data model reconciles order.

Production checklist

Before the build phase begins, confirm the following based on spike findings:

Ready to verify?

[ ] The measured p95 latency from the production network location is within the feature's latency budget.
[ ] The latency holds under the estimated production message rate, not just under the vendor's advertised ceiling.
[ ] Clock ownership is established — the data model knows which timestamp to trust for ordering.
[ ] Reconnection semantics are documented for each failure scenario (graceful shutdown, network interruption, idle timeout).
[ ] Message delivery semantics are established — at-most-once, at-least-once, or exactly-once — and the production design handles duplicates or gaps accordingly.
[ ] The client library's automatic reconnection behavior (or lack thereof) is confirmed with evidence, not assumed from documentation.
[ ] Rate-limit ceilings for the production tier are confirmed, and the production design stays within them with headroom for bursts.
[ ] The spike harness and its log output are preserved in the repository so findings can be re-verified during build.
[ ] Every conclusion in the spike report traces to a specific log entry rather than vendor documentation.
[ ] A go/no-go decision has been made based on measured evidence, with known risks documented rather than deferred.

Ready to Implement This Guide?

Our team can implement these strategies for you, tailored to your specific business needs.

Schedule Consultation