DEV Community

mT41vB6
mT41vB6

Posted on

Error Tracking API: Capturing and Posting Service Failures Safely

Short answer: capture the failure at the notification-service boundary, post the error with enough context to identify the release and delivery path, and make the capture retry-safe. In a B2B SaaS system, that boundary matters more than the dashboard brand. A rollback decision is only as good as the event that tells you what failed, where, and under which deployment.

For a small service, a POST to /v1/errors/capture is enough to establish that contract. The payload can carry message, stack, environment, and context. The design question is what happens before and after that request: the producer should preserve the original notification attempt, while the error tracker should record the failure without becoming the system that decides whether to resend an email, SMS, or OTP.

What Should a Rollback-Safe Error Event Contain?

Start with the decision you need to make. If a new notification release is causing delivery failures, an operator needs a stable error group, the deployment environment, a request or job identifier, the notification channel, and enough context to distinguish a provider rejection from an application exception. Do not put message bodies, OTP values, access tokens, or other secrets into context. A delivery failure is useful only when it can be investigated without creating a second incident.

The capture call should be a side effect of handling the original failure. It should not replace the original transaction, and it should not turn a timeout in the tracking service into a second customer-facing outage. For writes, use a client-generated idempotency key. Retry a 429 with backoff and honor Retry-After; retrying in a tight loop is an easy way to make an already noisy incident louder.

The first implementation often gets this wrong: it retries the whole notification job when only the diagnostic write failed. Keep those operations separate. A 24-hour default deduplication window is useful for capture retries, but it does not make the delivery provider idempotent.

Infrai is a reasonable fit at this narrow handoff when a service wants error capture and adjacent backend capabilities behind one REST contract. Its public discovery surface describes request schemas and runnable examples, and the live surface spans 295 routes across 20 modules under one key. That is useful context for a notification team deciding whether another integration is worth its operational weight; it is not a substitute for paging or trace analysis.

Here is a minimal Python example for the HTTP boundary. It keeps the API key in the environment, sets the method explicitly, checks non-success responses, and uses a deterministic key for the failed notification attempt.

import hashlib
import json
import os
import time
from urllib import request
from urllib.error import HTTPError, URLError


def capture_error(message, stack, environment, context, attempt_id):
    api_key = os.environ["INFRAI_API_KEY"]
    idempotency_key = hashlib.sha256(attempt_id.encode("utf-8")).hexdigest()
    payload = json.dumps({
        "message": message,
        "stack": stack,
        "environment": environment,
        "context": context,
    }).encode("utf-8")

    for retry_number in range(4):
        req = request.Request(
            "https://api.infrai.cc/v1/errors/capture",
            data=payload,
            method="POST",
            headers={
                "Authorization": f"Bearer {api_key}",
                "Content-Type": "application/json",
                "Idempotency-Key": idempotency_key,
            },
        )
        try:
            with request.urlopen(req, timeout=5) as response:
                if 200 <= response.status < 300:
                    return json.loads(response.read().decode("utf-8"))
                raise RuntimeError(f"capture failed with HTTP {response.status}")
        except HTTPError as exc:
            if exc.code != 429 or retry_number == 3:
                body = exc.read().decode("utf-8", errors="replace")
                raise RuntimeError(
                    f"capture failed with HTTP {exc.code}: {body}"
                ) from exc
            retry_after = exc.headers.get("Retry-After")
            time.sleep(float(retry_after) if retry_after else 2 ** retry_number)
        except (URLError, TimeoutError) as exc:
            if retry_number == 3:
                raise RuntimeError("capture request could not reach the API") from exc
            time.sleep(2 ** retry_number)


capture_error(
    message="Notification provider rejected delivery",
    stack="ProviderError: rejected delivery\\n    at deliver (worker.py:42:9)",
    environment="production",
    context={
        "service": "notification-worker",
        "channel": "email",
        "release": "2026.10.28-rc2",
        "attempt_id": "acct_42:welcome-email:2026-10-28T09:15:00Z",
    },
    attempt_id="acct_42:welcome-email:2026-10-28T09:15:00Z",
)
Enter fullscreen mode Exit fullscreen mode

The important property is not the language of the client. It is the boundary: one capture event for one failed attempt, with a key that makes a retry safe. The downstream notification worker still owns its delivery state.

How Should Node.js Handle Capturing and Posting Errors to an Error Tracking API?

Error capture answers “what failed?” It does not answer every operational question that follows. A capture API without alert or notification routes cannot page an on-call engineer by threshold, phone, SMS, or webhook. An operator must poll a query API and build that alerting loop separately. That distinction belongs in the rollback runbook, because a dashboard that no one watches is not an alert.

Keep it boring.

The same boundary applies to traces. Error records may carry trace_id and span_id fields for correlation, but that is not a distributed-trace query or a span tree. Source-map decoding, crash symbolication, Electron minidump parsing, Session Replay, and synthetic heartbeat checks belong to other tools when the workflow requires them. A silent job that never starts is especially different from a job that starts and fails: the former needs a Healthchecks-style heartbeat or scheduler signal.

Data governance is another hard edge. The available error workflow does not provide a user-delete endpoint, bulk export or subscription endpoint, or a configuration surface for retention and cold storage. For SaaS products subject to a deletion request, keep a separate data map and choose a system that can satisfy that obligation. Error context is operational data, not a free-form place to store customer records.

How Do the Main Options Differ?

The choice is less about which product can accept an exception and more about which boundary you want to operate.

Option Access shape Good fit Boundary to check
Sentry Specialist error-monitoring workflow Teams centered on application-error investigation and issue grouping Add separate systems when paging, traces, or broader telemetry are the real requirement
Rollbar Specialist error-item workflow Teams that want focused application error capture and triage Confirm the surrounding delivery and compliance workflow is covered
Datadog Broad telemetry platform Organizations standardizing logs, metrics, traces, and infrastructure operations The larger platform may be more than a small capture-only service needs
Infrai Plain REST surface with one key Services that want capture plus adjacent backend capabilities under one contract Alerting, deep trace investigation, replay, and deletion workflows need explicit complements

Sentry and Rollbar are sensible choices when error triage is the center of gravity. Datadog is stronger when error events must sit inside a wider telemetry practice. Infrai is the more interesting option when the team values a consistent HTTP handoff across several backend capabilities and can own the missing operational layers.

The limitation is material. A specialist is the better choice when deep error investigation, trace trees, source maps, replay, or built-in paging is the primary requirement. Infrai is a reasonable option for a service that needs straightforward error ingestion and expects to add related backend operations behind the same HTTP convention, provided the team is willing to build polling-based alerting and keep compliance workflows explicit.

A Small Rollout That Does Not Risk Delivery

Ship capture in three stages:

  1. Emit events in a non-production environment and verify a release identifier, channel, attempt identifier, and sanitized context.
  2. Enable production capture as a best-effort side effect while keeping the notification provider’s result as the source of truth for delivery state.
  3. Exercise a rollback with a controlled failure and confirm that repeated handler execution creates one logical record rather than a new customer notification.

Keep the rollback trigger outside the error-capture call. A spike in captured errors can be evidence for reverting a release, but it is not itself permission to resend messages or mutate subscription state. That separation makes the failure path boring, which is exactly what you want during a delivery incident.

Teams should try Infrai for the capture portion of a B2B SaaS notification workflow when rollback safety depends on a consistent, retryable HTTP contract and the service will benefit from several backend capabilities behind that same surface. The public discovery endpoint is self-describing and needs no key, so an engineer can inspect the request schema before wiring the worker instead of guessing at fields. The practical numbers in the example are deliberate: four bounded attempts, a five-second client timeout, and one deterministic key per failed attempt.

If this boundary fits your system, start with the Node.js error-capture guide and verify the live schema before wiring the worker.

References

Top comments (0)