pino logs for Sume API calls: job_id, request_id, redacted keys

Log every Sume call with pino child loggers that carry job_id and the error request_id, and redact the Authorization header so keys never reach the log store.

5 min readSume
All posts

Create one pino logger with redact set for the Authorization header and your signing secret, then bind a child logger to each job with log.child({ job_id }). Every line from that job's submit, polls and webhook now carries the same job_id, and a failed call also logs the request_id from Sume's error envelope. A support ticket then needs one string, not a time window.

The id to join on is the job id. It is what Jobs and results tells you to store from the submit response, and it is the job_id on the webhook, so submit logs, poll logs and webhook logs line up without a lookup table.

A logger that cannot leak the key

The helper below submits a video job, logs the outcome and returns the id. Note what it does not log: the Authorization header, the request body with the prompt if you treat prompts as sensitive, and the signing secret.

import pino from "pino";
const log = pino({
  redact: { paths: ["headers.authorization", "secret", "*.secret"], censor: "[redacted]" },
});
const key = process.env.SUME_API_KEY;
if (!key) throw new Error("SUME_API_KEY is empty");

export async function submit(prompt, idempotencyKey) {
  const l = log.child({ idempotency_key: idempotencyKey });
  const res = await fetch("https://api.sume.com/v1/videos", {
    method: "POST",
    headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json", "Idempotency-Key": idempotencyKey },
    body: JSON.stringify({ model: "sume/auto", prompt, duration: 5 }),
  });
  const body = await res.json();
  if (!res.ok) {
    l.error({ http_status: res.status, code: body.error?.code, request_id: body.error?.request_id }, "submit failed");
    throw new Error(body.error?.code ?? "submit_failed");
  }
  l.child({ job_id: body.id }).info({ status: body.status }, "job accepted");
  return body.id;
}

Which fields to log

Keep the set small and join on ids. Fields with unbounded values, such as prompts, belong in your own data store, not in every log line.

Fields worth logging on each Sume call (Sume docs, read 2026-10-04)
FieldWhere it comes fromWhy
job_idSubmit response id, webhook job_idPrimary join key across submit, polls and webhooks
idempotency_keyYour own header valueShows whether a retry reused the key
http_status and error.codeSubmit or poll response429 queue_full and rate_limited need different handling
error.request_idError envelopeWhat Sume support can look up for a failed call
status or eventPoll status, webhook eventjob.completed, job.failed or job.canceled

Caveats

  • Redaction paths match object structure, not strings. Log request headers under a headers key, or add the path you actually use.
  • Never log the signing secret or compare values in the failure path of a webhook check. Each delivery carries an x-sume-webhook-secret-fingerprint header, so you can compare secrets without printing them.
  • A log line is not a recovery plan. Keep the id in durable storage, because a restarted process needs it to resume polling instead of submitting again.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume