Vercel renamed Edge Requests: match Sume errors by code, not text

Vercel Edge Requests are now CDN Requests, and billing reads should use SkuId. Same rule for Sume errors: branch on error.code and request_id, never message.

5 min readSume
All posts

Vercel renamed Edge Requests to CDN Requests on September 30, and it is a pure rename. Per the changelog, pricing, limits and how usage is measured are unchanged, and metric IDs and aliases stay stable. One thing does move: the billing charges API reports the new name in ServiceName, so the changelog tells integrators to migrate to SkuId (Vercel changelog, read 2026-10-04).

The lesson for anyone calling an AI media API from a Vercel project is general. Display names get renamed; identifiers do not. Any dashboard, cost script or error handler that matches on a human-readable string breaks the day the string changes. Sume's API is built so you never have to match on text.

What Sume gives you that stays put

Every Sume error comes in one envelope with a machine-readable code, a request_id (also sent as the x-sume-request-id response header), and flags such as retryable, retry_after_seconds and next_action. The message is for people. The errors and credits page lists the codes, for example insufficient_credits on a 402, rate_limited and queue_full on a 429, and idempotency_conflict on a 409.

Two checks that look similar mean different things. A rate_limited 429 says your request budget is spent, and details.scope says whether it was the read or write budget. A queue_full 429 says your plan's generation capacity is full, and retrying harder does not widen it. Branching on code keeps those apart, and a status-text match would not.

Sume error codes to branch on (Sume docs, read 2026-10-04)
codeHTTPWhat your handler should do
insufficient_credits402Stop and add funds; do not retry
rate_limited429Wait retry_after_seconds, then retry
queue_full429Wait for capacity, retry with the same Idempotency-Key
idempotency_conflict409Fix the bug: same key, different payload
insufficient_scope403Use a key with the needed scope

A handler that never reads message

The function below turns a failed Sume response into one of four actions using only code, retryable and retry_after_seconds, and logs request_id so a single failed call can be found later. It also covers a non-JSON body, such as an HTML error page from a proxy, by falling back to the status.

type Action = "stop" | "retry" | "fix" | "unknown";

export async function classify(res: Response): Promise<{
  action: Action;
  waitMs: number;
  requestId: string | null;
}> {
  const requestId = res.headers.get("x-sume-request-id");
  let err: any = null;
  try {
    err = (await res.json())?.error ?? null;
  } catch {
    // not JSON
  }
  if (!err?.code) {
    const retry = res.status === 408 || res.status === 429 || res.status >= 500;
    return { action: retry ? "retry" : "unknown", waitMs: 2000, requestId };
  }
  const waitMs = (err.retry_after_seconds ?? 2) * 1000;
  if (err.code === "insufficient_credits") return { action: "stop", waitMs: 0, requestId };
  if (err.code === "idempotency_conflict") return { action: "fix", waitMs: 0, requestId };
  if (err.retryable) return { action: "retry", waitMs, requestId };
  return { action: "unknown", waitMs: 0, requestId };
}

Apply the same rule to your cost data

If a script on your side groups Vercel spend by service name, move it to SkuId as the changelog advises. For Sume spend, join on job_id or request_id rather than on a label, so a rename in either system cannot split a series. The log six fields guide lists what to keep per call.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume