Delivery Log Search & Filters

Delivery Log Search & Filters (Find the One Run That Matters)

Short, repeatable search patterns save hours when deliveries fail. This guide shows a pragmatic workflow and the exact delivery log search filters you should use to find the single run or attempt that caused the problem.

You’ll learn which fields matter, copy-paste queries, and how to interpret retries so you don’t mistake a transient attempt for a permanent failure.

Use these steps to match SendPromptly delivery runs to your app logs and decide: replay, fix endpoint, or update the template.

What a “delivery log” represents

A delivery log records a single delivery “run” for a message to a specific channel or endpoint — not the message as a whole.

One message can create multiple “runs” (per channel/endpoint)

  • Each channel (webhook, email provider, SMS gateway) gets its own run.
  • Search by endpoint/channel to avoid inspecting the wrong run.

A run includes attempts (initial + retries)

  • A run contains the initial attempt and all retries (status changes as attempts are added).
  • Look at the latest attempt timestamp to see the current state.

Common gotcha: Expecting one log entry per message — you’ll often see multiple runs and multiple attempts; always inspect the run for the channel you care about.

The filters that solve 90% of incidents

Use focused delivery log search filters first — they reduce noise and get you to the failing attempt fast.

  • Start narrow: event_key + time window + endpoint.
  • Add status only after narrowing by event or idempotency/correlation.

Micro checklist:

  • Search event_key first
  • Narrow by endpoint or channel
  • Tighten the time window (±5 minutes)
  • Filter status=failed to find problematic runs

Filter by event key (event_key)

Use event_key when you know the business event (e.g., order.created). It’s the fastest way to surface relevant runs.

Filter by status (success vs failed vs retrying)

  • success = final 2xx run
  • failed = run ended without success
  • retrying = still in backoff

Filter by endpoint / channel (which webhook URL?)

Always include the endpoint dimension — a single event can deliver to multiple endpoints with different outcomes.

Filter by time window (tighten the blast radius)

Start with a narrow window around the incident time and expand only if needed.

High-signal search fields

These fields let you pivot from SendPromptly to your app logs in seconds.

Idempotency key (ingest-time dedupe)

Use the idempotency key to find the exact run that was deduped or retried.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// Somewhere central in your app
$correlationId = request()->header('X-Correlation-Id') ?? (string) \Illuminate\Support\Str::uuid();

$event = [
  'event_key' => 'order.created',
  'recipient' => ['email' => $user->email],
  'payload' => [
    'order_id' => $order->id,
    'correlation_id' => $correlationId,
  ],
];

// Use this value as your SendPromptly Idempotency-Key
$idempotencyKey = "order.created:{$order->id}";

Correlation ID (your trace ID)

Log and search by correlation_id to join SendPromptly runs with your application traces.

1
2
3
4
5
\Log::info('sendpromptly.delivery.debug', [
  'correlation_id' => $payload['correlation_id'] ?? null,
  'event_key' => $eventKey ?? null,
  'order_id' => $payload['order_id'] ?? null,
]);

Provider message id / external id (email providers)

Use provider IDs when diagnosing downstream provider issues.

Common gotcha: Confusing idempotency_key and correlation_id — the former prevents duplicate ingestion; the latter ties logs together.

Interpreting retries correctly

Understand what counts as success and what triggers retries; this prevents wasted investigation.

  • Success: strictly HTTP 2xx.
  • Non-2xx (including 4xx/5xx and timeouts) can trigger retries based on delivery rules.
OutcomeWhat it meansAction to take
2xxDelivery succeededNo replay needed
4xxContract/authorization issueFix consumer/credentials
5xx / timeoutReceiver/server issueFix endpoint or retry

Common gotcha: Timeouts look like “no response” but count as failures and will be retried.

Debug recipe (copy/paste workflow)

  1. Start with status=failed and event_key (or idempotency_key).
  2. Drill into the run → inspect the last attempt’s response body and headers.
  3. If signature headers are missing or invalid, fix verification or rotation.
  4. Decide: replay the run, fix the endpoint, or correct a template/payload.

Minimal test snippet:

1
2
3
4
5
6
7
8
9
curl -i -X POST https://app.sendpromptly.com/api/v1/events \
  -H "Authorization: Bearer sp_dev_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Idempotency-Key: debug-search-001" \
  -H "Content-Type: application/json" \
  -d '{
    "event_key":"order.created",
    "recipient":{"email":"[email protected]"},
    "payload":{"order_id":"O-1001","correlation_id":"cid-1001"}
  }'

Expected: 201 (or success response). In Message Log you can:

  • Search order.created
  • Filter status failed if you intentionally break the endpoint
  • Search cid-1001

Open the Sample Project, trigger one event, then use these filters to locate the run in under 30 seconds.

Common failure modes

  • Searching too broadly (no time window) → hundreds of results.
  • Not filtering by endpoint/channel → inspecting the wrong run.
  • Misreading “failed attempt” as “failed message” (later attempts can succeed).
  • Treating 401/403/404 as transient — they retry but won’t succeed until fixed.
  • Missing correlation IDs → can’t join app logs with delivery runs.
  • Not accounting for timeouts — looks like “no response” but counts as failure.

Micro checklist:

  • Always add time window + endpoint
  • Use correlation or idempotency key for exact matches
  • Inspect the last attempt’s response body and headers

SendPromptly webhook delivery rules: success is HTTP 2xx, non-2xx triggers retries using exponential backoff, and webhooks are signed via X-SP-Timestamp / X-SP-Signature.

Key takeaways

  • Start narrow: event_key + endpoint + tight time window.
  • Use correlation_id or idempotency_key to join logs quickly.
  • Success is HTTP 2xx; treat timeouts as failures.
  • Inspect the last attempt before deciding to replay.
  • Use Message Log to confirm replay vs fix decisions.